#Load in MBB - Statistic Tracking Report csv
stats <- read.csv("data-sets/data-sets-uncompressed/data-sets-compressed/Reactive Strength Index/MBB - Statistic Tracking Report.csv")

# Load in ACWR - Kinexon MBB
kinexon_ACWR <- read.csv("data-sets/data-sets-uncompressed/data-sets-compressed/Reactive Strength Index/ACWR - Kinexon MBB.csv")

#Loading in VALD - Dynamo MBB
VALD_dynamo <- read.csv("data-sets/data-sets-uncompressed/data-sets-compressed/Reactive Strength Index/VALD - Dynamo MBB.csv")

# Load in VALD - ForceDecks MBB csv
VALD_ForceDecks <- read.csv("data-sets/data-sets-uncompressed/data-sets-compressed/Reactive Strength Index/VALD - ForceDecks MBB.csv")

# Load in Kinexon Session
kinexon_session <- read.csv("data-sets/data-sets-uncompressed/data-sets-compressed/Reactive Strength Index/Kinexon Session MBB.csv")

Data Cleaning

# Remove columns where all data points are NA
stats_clean <- stats |>
  select(where(~ !all(is.na(.))))


# If all three date columns are equal, remove the redundant ones
if (all(stats_clean$Date == stats_clean$Date.Reverse, na.rm = TRUE) &&
    all(stats_clean$Date == stats_clean$Session.Date, na.rm = TRUE)) {
  
  stats_clean <- stats_clean |>
    select(-c(Date.Reverse, Session.Date))
}


# Convert if Date column is NOT already in Date format
if (!inherits(stats_clean$Date, "Date")) {
  stats_clean <- stats_clean %>%
    mutate(Date = as.Date(Date, format = "%m/%d/%Y"))
}
# Confirm it's now in Date format
class(stats_clean$Date)

stats_clean <- stats_clean[!is.na(stats_clean$Plus..Minus),]

# Add more stats
stats_clean <- stats_clean %>%
  filter(Date >= as.Date("2024-09-20", '%Y-%m-%d')) %>%
  group_by(anon_id) %>%
  mutate(Player.Average.Rebounds = mean(na.omit(Rebounds)),
         Player.Average.Steals = mean(na.omit(Steals)),
         Player.Average.Assists = mean(na.omit(Assists)),
         Player.Average.Turnovers = mean(na.omit(Turnovers)),
         Player.Average.Points.Scored = mean(na.omit(Points.Scored)),
         Player.Median.Rebounds = median(na.omit(Rebounds)),
         Player.Median.Steals = median(na.omit(Steals)),
         Player.Median.Assists = median(na.omit(Assists)),
         Player.Median.Turnovers = median(na.omit(Turnovers)),
         Player.Median.Points.Scored = median(na.omit(Points.Scored))) %>%
  ungroup() %>%
  group_by(Date) %>%
  mutate(Team.Rebounds = sum(na.omit(Rebounds)),
         Team.Steals = sum(na.omit(Steals)),
         Team.Assists = sum(na.omit(Assists)),
         Team.Turnovers = sum(na.omit(Turnovers)),
         Team.Points.Scored = as.numeric(str_split(Game.Score, "-")[[1]][1])) %>%
  ungroup() %>%
  mutate(Team.Average.Rebounds = mean(Team.Rebounds),
         Team.Average.Steals = mean(Team.Steals),
         Team.Average.Assists = mean(Team.Assists),
         Team.Average.Turnovers = mean(Team.Turnovers),
         Team.Average.Points.Scored = mean(Team.Points.Scored)) %>%
  mutate(Player.Good.Game = ifelse(Rebounds >= Player.Median.Rebounds & Steals >= Player.Median.Steals & Assists >= Player.Median.Assists,1,0),
         Player.Bad.Game = ifelse(Rebounds < Player.Median.Rebounds & Steals < Player.Median.Steals & Assists < Player.Median.Assists,1,0),
         Team.Good.Game = ifelse(Team.Rebounds >= median(Team.Rebounds) & Team.Steals >= median(Team.Steals) & Team.Assists >= median(Team.Assists),1,0),
         Team.Bad.Game = ifelse(Team.Rebounds < median(Team.Rebounds) & Team.Steals < median(Team.Steals) & Team.Assists < median(Team.Assists),1,0)) %>%
  select(-c(Sport, Day.of.Week, Month, Month.with.Number, Year, Number.of.Competitions.Won, Total.Daily.Competitions.Available, Total.Competitions.Won, Total.Game.Minutes, Offensive.Rebounds, Defensive.Rebounds, Buff.Plays, Percentage.Daily.of.Competitions.Won)) %>%
  filter(!(anon_id %in% c("ID_10", "ID_14", "ID_15", "ID_18", "ID_54", "ID_64")))
# Remove columns where all data points are NA
kinexon_ACWR_clean <- kinexon_ACWR |>
  select(where(~ !all(is.na(.))))



# If all three date columns are equal, remove the redundant ones
if (all(kinexon_ACWR_clean$Date == kinexon_ACWR_clean$Date.Reverse, na.rm = TRUE) &&
    all(kinexon_ACWR_clean$Date == kinexon_ACWR_clean$Session.Date, na.rm = TRUE)) {
  
  kinexon_ACWR_clean <- kinexon_ACWR_clean |>
    select(-c(Date.Reverse, Session.Date))
}


# Convert if Date column is NOT already in Date format
if (!inherits(kinexon_ACWR_clean$Date, "Date")) {
  kinexon_ACWR_clean <- kinexon_ACWR_clean %>%
    mutate(Date = as.Date(Date, format = "%m/%d/%Y"))
}
# Confirm it's now in Date format
class(kinexon_ACWR_clean$Date)


# Selecting only relevant columns
kinexon_ACWR_clean <- kinexon_ACWR_clean %>%
  select(anon_id, Date, Day.of.the.Week, Month, Year, Position, Session.Type, Session.Description, Practice.Classification, Last.7.Day.Acceleration.Load, Today.s.Acceleration.Load, Acceleration.Load.ACWR, Acceleration.Load.EWMA.ACWR, Acute.Total.Acceleration.Load, Acute.Total.Acceleration.Load.EWMA, Chronic.Total.Acceleration.Load, Chronic.Total.Acceleration.Load.EWMA, Total.Low.Acceleration.Load, Total.Medium.Acceleration.Load, Total.High.Acceleration.Load, Total.Very.High.Acceleration.Load, Last.7.Day.Total.Jump.Load, Today.s.Jump.Load, Total.Jump.Load.ACWR, Acute.Total.Jump.Load, Acute.Total.Jump.Load.EWMA, Chronic.Total.Jump.Load, Chronic.Total.Jump.Load.EWMA, Last.7.Day.Total.Minutes, Today.s.Minutes, Minutes.ACWR, Minutes.EWMA.ACWR, Acute.Minutes, Acute.Minutes.EWMA, Chronic.Minutes, Chronic.Minutes.EWMA, Total.Distance.EWMA.ACWR)
#selecting important variables, removing rows with missing data, only selecting hand movements
VALD_dynamo_clean <- VALD_dynamo %>%
  filter(Body.Region == "Hand") %>%
  mutate(Right.Side = ifelse(Repetition.Type.Laterality=="RightSide",1,0)) %>%
  select(anon_id,   Date, Max.Force.Newtons, Avg.Force.Newtons, Max.Impulse.Newton.Seconds,  Max.Rate.Of.Force.Development.Newtons.Per.Second,  Avg.Rate.Of.Force.Development.Newtons.Per.Second,   Min.Time.To.Peak.Force.Seconds, Start.Offset.Seconds, Repetition.Duration.Seconds,  Repetition.Max.Force.Newtons,   Impulse.Newton.Seconds, Rate.Of.Force.Development.Newtons.Per.Second,   Time.To.Peak.Force.Seconds,Right.Side) %>%
  na.omit()

# Convert if Date column is NOT already in Date format
if (!inherits(VALD_dynamo_clean$Date, "Date")) {
  VALD_dynamo_clean<- VALD_dynamo_clean%>%
    mutate(Date = as.Date(Date, format = "%m/%d/%Y"))
}
# Confirm it's now in Date format
class(VALD_dynamo_clean$Date)


#This data set contains information from each individual hand in a strength test meaning that there are two measurements per day for each player. This makes it hard to understand in plots especially when plotted like time series data. For future reference, it might be useful to take an average of both sides or note that there is a difference in each hand and plot the left and rights sides separately.

#### Note that you have to group on id and the date in order to get a valid average of both sides for a specific day for each individual player. 
VALD_ForceDecks_clean <- VALD_ForceDecks %>%
  select(where(~ !all(is.na(.)))) %>%
  mutate(X=1:3384) %>%
  filter(Test.Type == "DJ") %>%
  select(X,anon_id, Date, Week, Position, Test.Type, Weight..kg., Trial, Flight.Time..s., Jump.Height..Flight.Time...cm., Eccentric.Concentric.Mean.Force.Ratio, Contact.Time..s., RSI..JH..Flight.Time..Contact.Time., RSI..Flight.Time.Contact.Time., Drop.Height..cm.)%>%
  mutate(RSI..m.per.s. = (Jump.Height..Flight.Time...cm./100)/Contact.Time..s.,
         Date = as.Date(Date, '%m/%d/%Y')) %>%
  group_by(Date, anon_id) %>%
  mutate(Weight..kg. = mean(na.omit(Weight..kg.)),
         Player.Average.RSI..m.per.s. = mean(RSI..m.per.s.)) %>%
  ungroup() %>%
  group_by(Date) %>%
  mutate(Team.Average.RSI..m.per.s. = mean(na.omit(RSI..m.per.s.)))
# Remove columns where all data points are NA
kinexon_session_clean <- kinexon_session |>
  select(where(~ !all(is.na(.))))


# Convert if Date column is NOT already in Date format
if (!inherits(kinexon_session_clean$Date, "Date")) {
  kinexon_session_clean <- kinexon_session_clean %>%
    mutate(Date = as.Date(Date, format = "%m/%d/%Y"))
}
# Confirm it's now in Date format
class(kinexon_session_clean$Date)
[1] "Date"
# Filter to only include data from this season
kinexon_session_clean <- kinexon_session_clean |>
  filter(Date >= as.Date("2024-6-01"))

##Analysis

Question 1

Question 2

Question 3:

Calculate load of 7, 3, and 1, day before test day including test date.

# Filter to only have data from this season
RSI <- VALD_ForceDecks_clean |>
  filter(Date >= as.Date("2024-10-10")) |>
  select(anon_id, Date, RSI..m.per.s., Trial) |>
  arrange(anon_id, Date) |>
  group_by(anon_id, Date) |>
  mutate(Daily.Avg.RSI..m.per.s = mean(RSI..m.per.s.)) |>
  ungroup()


# Plot RSI over season
ggplot(RSI, aes(x=Date, y=Daily.Avg.RSI..m.per.s, color=anon_id)) +
  geom_point() +
  geom_smooth(method="lm", se=FALSE) +
  labs(title = "Athlete RSI Scores Throughout Season") +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# Create load data frame containing columns relevant to load
load <- kinexon_session_clean |>
  filter(Date >= as.Date("2024-10-10")) |>
  select(anon_id, Date, Daily.Total.Accel.Load.Accum, Jump.Load) |>
  filter(!is.na(Daily.Total.Accel.Load.Accum))


# Look into Daily Acceleration Load for one athlete
id_40_load <- load |>
  filter(anon_id == "ID_40")
# Plot of ID_40's Daily Accel Load
ggplot(data = id_40_load, aes(x = Date, y = Daily.Total.Accel.Load.Accum)) +
  geom_point() +
  geom_line() +
  labs(title = "ID_40 Daily Acceleration Load") +
  theme_classic()



# Plot of all athlete's daily accel load throughout season
ggplot(data = load, aes(x=Date, y=Daily.Total.Accel.Load.Accum, color=anon_id)) +
  geom_point() +
  geom_smooth(method = "lm", se = FALSE) +
  labs(title = "2024-25 Baskteball Athlete's Daily Acceleration Load") +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# Plot of all athlete's daily jump load throughout season
ggplot(data = load, aes(x=Date, y=Jump.Load, color=anon_id)) +
  geom_point() +
  geom_smooth(method = "lm", se = FALSE) +
  labs(title = "2024-25 Baskteball Athlete's Daily Jump Load") +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

The graphs seem to show that for most athletes, RSI scores increased throughout the season, while daily acceleration load decreased and jump load about stayed the same.

# Calculate the average and total acceleration and jump load in the last 7, 3, and 2 days.

## Last 7 days not last 7 sessions
# Include that day in the last 7. (That day and the 6 days before that day, total of 7)
rolling_NDay_load <- load |>
  filter(!is.na(Daily.Total.Accel.Load.Accum)) |>
  arrange(anon_id, Date) |>
  group_by(anon_id) |>
  group_split() |>
  map_dfr(~{
    athlete_data <- .
    map_dfr(seq_len(nrow(athlete_data)), function(i) {
      current_row <- athlete_data[i, ]
      past_week <- athlete_data |>
        filter(Date <= current_row$Date & Date > current_row$Date - days(7)) # (<=) includes that day in the last 7.
      
      current_row |>
        mutate(
          Avg..7Day..Accel.Load = mean(past_week$Daily.Total.Accel.Load.Accum, na.rm = TRUE),
          Total..7Day..Accel.Load = sum(past_week$Daily.Total.Accel.Load.Accum, na.rm = TRUE),
          Avg..7Day..Jump.Load = mean(past_week$Jump.Load, na.rm = TRUE),
          Total..7Day..Jump.Load = sum(past_week$Jump.Load, na.rm = TRUE),
          Days.Used.7Day = nrow(past_week)
        )
    })
  })



# Add 3 Day Load
# That day and the two days before it
rolling_NDay_load <- rolling_NDay_load |>
  arrange(anon_id, Date) |>
  group_by(anon_id) |>
  group_split() |>
  map_dfr(~{
    athlete_data <- .
    map_dfr(seq_len(nrow(athlete_data)), function(i) {
      current_row <- athlete_data[i, ]
      past_3days <- athlete_data |>
        filter(Date <= current_row$Date & Date > current_row$Date - days(3))  # includes current day

      current_row |>
        mutate(
          Avg..3Day..Accel.Load = mean(past_3days$Daily.Total.Accel.Load.Accum, na.rm = TRUE),
          Total..3Day..Accel.Load = sum(past_3days$Daily.Total.Accel.Load.Accum, na.rm = TRUE),
          Avg..3Day..Jump.Load = mean(past_3days$Jump.Load, na.rm = TRUE),
          Total..3Day..Jump.Load = sum(past_3days$Jump.Load, na.rm = TRUE),
          Days.Used.3Day = nrow(past_3days)
        )
    })
  })



# Add 2 Day Load
# That day and the day before it
rolling_NDay_load <- rolling_NDay_load |>
  arrange(anon_id, Date) |>
  group_by(anon_id) |>
  group_split() |>
  map_dfr(~{
    athlete_data <- .
    map_dfr(seq_len(nrow(athlete_data)), function(i) {
      current_row <- athlete_data[i, ]
      past_2days <- athlete_data |>
        filter(Date <= current_row$Date & Date > current_row$Date - days(2))  # includes current day

      current_row |>
        mutate(
          Avg..2Day..Accel.Load = mean(past_2days$Daily.Total.Accel.Load.Accum, na.rm = TRUE),
          Total..2Day..Accel.Load = sum(past_2days$Daily.Total.Accel.Load.Accum, na.rm = TRUE),
          Avg..2Day..Jump.Load = mean(past_2days$Jump.Load, na.rm = TRUE),
          Total..2Day..Jump.Load = sum(past_2days$Jump.Load, na.rm = TRUE),
          Days.Used.2Day = nrow(past_2days)
        )
    })
  })
RSI_daily_avg <- RSI |>
  distinct(anon_id, Date, Daily.Avg.RSI..m.per.s)

# Merge the RSI and rolling day load data frames
load_and_RSI <- RSI_daily_avg |>
  left_join(
    rolling_NDay_load,
    by = "anon_id",
    relationship = "many-to-many"
  ) |>
  filter(Date.y <= Date.x & Date.y >= Date.x - days(7)) |> # <= includes same day. On days when RSI and accel load are measured, accel load is measured first, meaning we should include it.
  group_by(anon_id, Date.x) |>
  slice_max(Date.y, n = 1) |>  # Keep the most recent load data before RSI
  ungroup() |>
  rename(
    RSI_Date = Date.x,
    Load_Date = Date.y,
    RSI = Daily.Avg.RSI..m.per.s
  )


# Now that only have load data for N days before a test (and that day) we rename the columns
load_and_RSI <- load_and_RSI |> rename(
  `TD-6..Avg..Accel.Load` = Avg..7Day..Accel.Load,
  `TD-6..Total..Accel.Load` = Total..7Day..Accel.Load,
  `TD-6..Avg..Jump.Load` = Avg..7Day..Jump.Load,
  `TD-6..Total..Jump.Load` = Total..7Day..Jump.Load,

  `TD-2..Avg..Accel.Load` = Avg..3Day..Accel.Load,
  `TD-2..Total..Accel.Load` = Total..3Day..Accel.Load,
  `TD-2..Avg..Jump.Load` = Avg..3Day..Jump.Load,
  `TD-2..Total..Jump.Load` = Total..3Day..Jump.Load,

  `TD-1..Avg..Accel.Load` = Avg..2Day..Accel.Load,
  `TD-1..Total..Accel.Load` = Total..2Day..Accel.Load,
  `TD-1..Avg..Jump.Load` = Avg..2Day..Jump.Load,
  `TD-1..Total..Jump.Load` = Total..2Day..Jump.Load
)

# TD-6 means the load data from the last 6 days before the test day and the test day
# (load data from the last 6 days and the test day)
# TD-2 means the load data from the two days prior to the test day and the test day
# TD-1 means the data from the day before the test day and data from the test day
# Correlation Tests for each variable vs RSI

# Define target variables
load_vars <- c(
  "TD-6..Avg..Accel.Load", "TD-6..Total..Accel.Load",
  "TD-2..Avg..Accel.Load", "TD-2..Total..Accel.Load",
  "TD-1..Avg..Accel.Load", "TD-1..Total..Accel.Load",
  "TD-6..Avg..Jump.Load",  "TD-6..Total..Jump.Load",
  "TD-2..Avg..Jump.Load",  "TD-2..Total..Jump.Load",
  "TD-1..Avg..Jump.Load",  "TD-1..Total..Jump.Load"
)

# Compute correlations
correlation_results <- map_dfr(load_vars, function(var) {
  pearson <- cor(load_and_RSI$RSI, load_and_RSI[[var]], use = "complete.obs")
  spearman <- cor(load_and_RSI$RSI, load_and_RSI[[var]], method = "spearman", use = "complete.obs")
  
  tibble(
    Variable = var,
    Pearson = round(pearson, 3),
    Spearman = round(spearman, 3)
  )
})


kable(correlation_results)
Variable Pearson Spearman
TD-6..Avg..Accel.Load 0.008 0.023
TD-6..Total..Accel.Load 0.042 0.055
TD-2..Avg..Accel.Load 0.019 0.027
TD-2..Total..Accel.Load -0.014 -0.042
TD-1..Avg..Accel.Load -0.048 -0.047
TD-1..Total..Accel.Load -0.025 -0.010
TD-6..Avg..Jump.Load 0.258 0.231
TD-6..Total..Jump.Load 0.238 0.230
TD-2..Avg..Jump.Load 0.243 0.229
TD-2..Total..Jump.Load 0.160 0.105
TD-1..Avg..Jump.Load 0.210 0.205
TD-1..Total..Jump.Load 0.189 0.180
NA
# AVERAGE ACCEL LOAD:
# Relationship between RSI and 7-Day Average Acceleration Load
ggplot(load_and_RSI, aes(x = `TD-6..Avg..Accel.Load`, y = RSI)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "loess", se = FALSE, color = "#CFB87C") +
  labs(
    title = "RSI vs. 7-Day Avg Accel Load",
    x = "7-Day Avg Accel Load (TD-6 to TD)",
    y = "RSI (m/s)"
  ) +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# Relationship between RSI and 3-Day Average Acceleration Load
ggplot(load_and_RSI, aes(x = `TD-2..Avg..Accel.Load`, y = RSI)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "loess", se = FALSE, color = "#CFB87C") +
  labs(
    title = "RSI vs. 3-Day Avg Accel Load",
    x = "3-Day Avg Accel Load (TD-2 to TD)",
    y = "RSI (m/s)"
  ) +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# Relationship between RSI and 2-Day Average Acceleration Load
ggplot(load_and_RSI, aes(x = `TD-1..Avg..Accel.Load`, y = RSI)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "loess", se = FALSE, color = "#CFB87C") +
  labs(
    title = "RSI vs. 2-Day Avg Accel Load",
    x = "2-Day Avg Accel Load (TD-1 to TD)",
    y = "RSI (m/s)"
  ) +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# TOTAL ACCEL LOAD:
# RSI and 7-Day Total Acceleration Load
ggplot(load_and_RSI, aes(x = `TD-6..Total..Accel.Load`, y = RSI)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "loess", se = FALSE, color = "#CFB87C") +
  labs(
    title = "RSI vs. 7-Day Avg Accel Load",
    x = "7-Day Total Accel Load (TD-6 to TD)",
    y = "RSI (m/s)"
  ) +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# RSI and 3-Day Total Acceleration Load
ggplot(load_and_RSI, aes(x = `TD-2..Total..Accel.Load`, y = RSI)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "loess", se = FALSE, color = "#CFB87C") +
  labs(
    title = "RSI vs. 3-Day Avg Accel Load",
    x = "3-Day Total Accel Load (TD-2 to TD)",
    y = "RSI (m/s)"
  ) +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# RSI and 2-Day Average Acceleration Load
ggplot(load_and_RSI, aes(x = `TD-1..Total..Accel.Load`, y = RSI)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "loess", se = FALSE, color = "#CFB87C") +
  labs(
    title = "RSI vs. 2-Day Avg Accel Load",
    x = "2-Day Total Accel Load (TD-1 to TD)",
    y = "RSI (m/s)"
  ) +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# AVERAGE JUMP LOAD:
# RSI and 7-Day Average Jump Load
ggplot(load_and_RSI, aes(x = `TD-6..Avg..Jump.Load`, y = RSI)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "loess", se = FALSE, color = "#CFB87C") +
  labs(
    title = "RSI vs. 7-Day Avg Jump Load",
    x = "7-Day Avg Jump Load (TD-6 to TD)",
    y = "RSI (m/s)"
  ) +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# RSI and 3-Day Average Jump Load
ggplot(load_and_RSI, aes(x = `TD-2..Avg..Jump.Load`, y = RSI)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "loess", se = FALSE, color = "#CFB87C") +
  labs(
    title = "RSI vs. 3-Day Avg Jump Load",
    x = "3-Day Avg Jump Load (TD-2 to TD)",
    y = "RSI (m/s)"
  ) +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# RSI and 2-Day Average Jump Load
ggplot(load_and_RSI, aes(x = `TD-1..Avg..Jump.Load`, y = RSI)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "loess", se = FALSE, color = "#CFB87C") +
  labs(
    title = "RSI vs. 2-Day Avg Jump Load",
    x = "2-Day Avg Jump Load (TD-1 to TD)",
    y = "RSI (m/s)"
  ) +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# TOTAL JUMP LOAD:
# RSI and 7-Day Total Jump Load
ggplot(load_and_RSI, aes(x = `TD-6..Total..Jump.Load`, y = RSI)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "loess", se = FALSE, color = "#CFB87C") +
  labs(
    title = "RSI vs. 7-Day Avg Jump Load",
    x = "7-Day Total Jump Load (TD-6 to TD)",
    y = "RSI (m/s)"
  ) +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# RSI and 3-Day Total Jump Load
ggplot(load_and_RSI, aes(x = `TD-2..Total..Jump.Load`, y = RSI)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "loess", se = FALSE, color = "#CFB87C") +
  labs(
    title = "RSI vs. 3-Day Avg Jump Load",
    x = "3-Day Total Jump Load (TD-2 to TD)",
    y = "RSI (m/s)"
  ) +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# RSI and 2-Day Total Jump Load
ggplot(load_and_RSI, aes(x = `TD-1..Total..Jump.Load`, y = RSI)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "loess", se = FALSE, color = "#CFB87C") +
  labs(
    title = "RSI vs. 2-Day Avg Jump Load",
    x = "2-Day Total Jump Load (TD-1 to TD)",
    y = "RSI (m/s)"
  ) +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# Plot for each athlete
unique_ids <- unique(load_and_RSI$anon_id)

for (id in unique_ids) {
  p <- ggplot(filter(load_and_RSI, anon_id == id),
              aes(x = `TD-6..Avg..Accel.Load`, y = RSI)) +
    geom_point() +
    geom_smooth(method = "loess", color = "#CFB87C") +
    labs(title = paste("RSI vs. Prior Week's Accel Load:", id),
         x = "Total Load Last 7 Days",
         y = "RSI")
   print(p)
   
}
`geom_smooth()` using formula = 'y ~ x'
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  span too small.   fewer data values than degrees of freedom.
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  pseudoinverse used at 710.48
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  neighborhood radius 133.28
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  reciprocal condition number  0
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  There are other near singularities as well. 6076.6
Warning in predLoess(object$y, object$x, newx = if (is.null(newdata)) object$x else if (is.data.frame(newdata)) as.matrix(model.frame(delete.response(terms(object)),  :
  span too small.   fewer data values than degrees of freedom.
Warning in predLoess(object$y, object$x, newx = if (is.null(newdata)) object$x else if (is.data.frame(newdata)) as.matrix(model.frame(delete.response(terms(object)),  :
  pseudoinverse used at 710.48
Warning in predLoess(object$y, object$x, newx = if (is.null(newdata)) object$x else if (is.data.frame(newdata)) as.matrix(model.frame(delete.response(terms(object)),  :
  neighborhood radius 133.28
Warning in predLoess(object$y, object$x, newx = if (is.null(newdata)) object$x else if (is.data.frame(newdata)) as.matrix(model.frame(delete.response(terms(object)),  :
  reciprocal condition number  0
Warning in predLoess(object$y, object$x, newx = if (is.null(newdata)) object$x else if (is.data.frame(newdata)) as.matrix(model.frame(delete.response(terms(object)),  :
  There are other near singularities as well. 6076.6
Warning in max(ids, na.rm = TRUE) :
  no non-missing arguments to max; returning -Inf
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  Chernobyl! trL>n 6
Warning in simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  Chernobyl! trL>n 6
Warning in sqrt(sum.squares/one.delta) : NaNs produced
Warning in stats::qt(level/2 + 0.5, pred$df) : NaNs produced
Warning in max(ids, na.rm = TRUE) :
  no non-missing arguments to max; returning -Inf
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'

# Correlation Tests for each variable vs RSI

# Calculate overall Pearson correlations for each variable
overall_corrs <- map_dfr(load_vars, ~ {
  load_and_RSI |> 
    summarize(
      r = cor(RSI, .data[[.x]], use = "complete.obs"),
      n = n()
    ) |> 
    mutate(variable = .x)
})

# Basic plot (no theming)
ggplot(overall_corrs, aes(x = reorder(variable, r), y = r)) +
  geom_col(fill = "#CFB87C") +
  geom_text(aes(label = round(r, 2)), 
            hjust = ifelse(overall_corrs$r >= 0, -0.1, 1.1),
            size = 3) +
  coord_flip() +
  labs(title = "Correlation Between Load Metrics and RSI",
       x = "Load Metric",
       y = "Pearson Correlation (r)") +
  scale_x_discrete(labels = function(x) gsub("\\.\\.", ": ", x)) +  # Clean names
  theme_classic()

NA
NA

Jump Load seems to be more correlated and even positively correlated than accel load.

# Per athlete accel load correlations with RSI

# ACCEL LOAD:
# Average 7 day accel load
per_athlete_corrs_avg <- load_and_RSI |>
  group_by(anon_id) |>
  summarize(
    r = cor(RSI, `TD-6..Avg..Accel.Load`, use = "complete.obs"),
    n = n()
  ) |>
  arrange(r)

ggplot(per_athlete_corrs_avg, aes(x = reorder(anon_id, r), y = r)) +
  geom_col(fill = "#CFB87C") +
  geom_text(aes(label = round(r, 2)), 
              hjust = ifelse(per_athlete_corrs_avg$r >= 0, -0.1, 1.1),
              size = 3.2,
              color = "#000000") +
  coord_flip() +
  labs(title = "Per Athlete Correlation Between Avg 7-Day Accel Load and RSI",
       x = "Athlete",
       y = "Correlation (r)") + 
  theme_classic()



# Total 7 day accel load
per_athlete_corrs_total <- load_and_RSI |>
  group_by(anon_id) |>
  summarize(
    r = cor(RSI, `TD-6..Total..Accel.Load`, use = "complete.obs"),
    n = n()
  ) |>
  arrange(r)

ggplot(per_athlete_corrs_total, aes(x = reorder(anon_id, r), y = r)) +
  geom_col(fill = "#CFB87C") +
  geom_text(aes(label = round(r, 2)), 
              hjust = ifelse(per_athlete_corrs_total$r >= 0, -0.1, 1.1),
              size = 3.2,
              color = "#000000") +
  coord_flip() +
  labs(title = "Per Athlete Correlation Between Total 7-Day Accel Load and RSI",
       x = "Athlete",
       y = "Correlation (r)") +
  theme_classic()




# Average 3 day accel load
per_athlete_corrs_avg <- load_and_RSI |>
  group_by(anon_id) |>
  summarize(
    r = cor(RSI, `TD-2..Avg..Accel.Load`, use = "complete.obs"),
    n = n()
  ) |>
  arrange(r)

ggplot(per_athlete_corrs_avg, aes(x = reorder(anon_id, r), y = r)) +
  geom_col(fill = "#CFB87C") +
  geom_text(aes(label = round(r, 2)), 
              hjust = ifelse(per_athlete_corrs_avg$r >= 0, -0.1, 1.1),
              size = 3.2,
              color = "#000000") +
  coord_flip() +
  labs(title = "Per Athlete Correlation Between Avg 3-Day Accel Load and RSI",
       x = "Athlete",
       y = "Correlation (r)") +
  theme_classic()



# Total 3 day accel load
per_athlete_corrs_total <- load_and_RSI |>
  group_by(anon_id) |>
  summarize(
    r = cor(RSI, `TD-2..Total..Accel.Load`, use = "complete.obs"),
    n = n()
  ) |>
  arrange(r)

ggplot(per_athlete_corrs_total, aes(x = reorder(anon_id, r), y = r)) +
  geom_col(fill = "#CFB87C") +
  geom_text(aes(label = round(r, 2)), 
              hjust = ifelse(per_athlete_corrs_total$r >= 0, -0.1, 1.1),
              size = 3.2,
              color = "#000000") +
  coord_flip() +
  labs(title = "Per Athlete Correlation Between Total 3-Day Accel Load and RSI",
       x = "Athlete",
       y = "Correlation (r)") +
  theme_classic()




# Average 2 day accel load
per_athlete_corrs_avg <- load_and_RSI |>
  group_by(anon_id) |>
  summarize(
    r = cor(RSI, `TD-1..Avg..Accel.Load`, use = "complete.obs"),
    n = n()
  ) |>
  arrange(r)

ggplot(per_athlete_corrs_avg, aes(x = reorder(anon_id, r), y = r)) +
  geom_col(fill = "#CFB87C") +
  geom_text(aes(label = round(r, 2)), 
              hjust = ifelse(per_athlete_corrs_avg$r >= 0, -0.1, 1.1),
              size = 3.2,
              color = "#000000") +
  coord_flip() +
  labs(title = "Per Athlete Correlation Between Avg 2-Day Accel Load and RSI",
       x = "Athlete",
       y = "Correlation (r)") +
  theme_classic()



# Total 2 day accel load
per_athlete_corrs_total <- load_and_RSI |>
  group_by(anon_id) |>
  summarize(
    r = cor(RSI, `TD-1..Total..Accel.Load`, use = "complete.obs"),
    n = n()
  ) |>
  arrange(r)

ggplot(per_athlete_corrs_total, aes(x = reorder(anon_id, r), y = r)) +
  geom_col(fill = "#CFB87C") +
  geom_text(aes(label = round(r, 2)), 
              hjust = ifelse(per_athlete_corrs_total$r >= 0, -0.1, 1.1),
              size = 3.2,
              color = "#000000") +
  coord_flip() +
  labs(title = "Per Athlete Correlation Between Total 2-Day Accel Load and RSI",
       x = "Athlete",
       y = "Correlation (r)") +
  theme_classic()

ID_64 seem to have a moderatley strong negative correlation between acceleration load and RSI.

# JUMP LOAD
# Average 7 day jump load
per_athlete_corrs_avg <- load_and_RSI |>
  group_by(anon_id) |>
  summarize(
    r = cor(RSI, `TD-6..Avg..Jump.Load`, use = "complete.obs"),
    n = n()
  ) |>
  arrange(r)

ggplot(per_athlete_corrs_avg, aes(x = reorder(anon_id, r), y = r)) +
  geom_col(fill = "#CFB87C") +
  geom_text(aes(label = round(r, 2)), 
              hjust = ifelse(per_athlete_corrs_avg$r >= 0, -0.1, 1.1),
              size = 3.2,
              color = "#000000") +
  coord_flip() +
  labs(title = "Per Athlete Correlation Between Avg 7-Day Jump Load and RSI",
       x = "Athlete",
       y = "Correlation (r)") +
  theme_classic()



# Total 7 day jump load
per_athlete_corrs_total <- load_and_RSI |>
  group_by(anon_id) |>
  summarize(
    r = cor(RSI, `TD-6..Total..Jump.Load`, use = "complete.obs"),
    n = n()
  ) |>
  arrange(r)

ggplot(per_athlete_corrs_total, aes(x = reorder(anon_id, r), y = r)) +
  geom_col(fill = "#CFB87C") +
  geom_text(aes(label = round(r, 2)), 
              hjust = ifelse(per_athlete_corrs_total$r >= 0, -0.1, 1.1),
              size = 3.2,
              color = "#000000") +
  coord_flip() +
  labs(title = "Per Athlete Correlation Between Total 7-Day Jump Load and RSI",
       x = "Athlete",
       y = "Correlation (r)") +
  theme_classic()




# Average 3 day jump load
per_athlete_corrs_avg <- load_and_RSI |>
  group_by(anon_id) |>
  summarize(
    r = cor(RSI, `TD-2..Avg..Jump.Load`, use = "complete.obs"),
    n = n()
  ) |>
  arrange(r)

ggplot(per_athlete_corrs_avg, aes(x = reorder(anon_id, r), y = r)) +
  geom_col(fill = "#CFB87C") +
  geom_text(aes(label = round(r, 2)), 
              hjust = ifelse(per_athlete_corrs_avg$r >= 0, -0.1, 1.1),
              size = 3.2,
              color = "#000000") +
  coord_flip() +
  labs(title = "Per Athlete Correlation Between Avg 3-Day Jump Load and RSI",
       x = "Athlete",
       y = "Correlation (r)") +
  theme_classic()



# Total 3 day jump load
per_athlete_corrs_total <- load_and_RSI |>
  group_by(anon_id) |>
  summarize(
    r = cor(RSI, `TD-2..Total..Jump.Load`, use = "complete.obs"),
    n = n()
  ) |>
  arrange(r)

ggplot(per_athlete_corrs_total, aes(x = reorder(anon_id, r), y = r)) +
  geom_col(fill = "#CFB87C") +
  geom_text(aes(label = round(r, 2)), 
              hjust = ifelse(per_athlete_corrs_total$r >= 0, -0.1, 1.1),
              size = 3.2,
              color = "#000000") +
  coord_flip() +
  labs(title = "Per Athlete Correlation Between Total 3-Day Jump Load and RSI",
       x = "Athlete",
       y = "Correlation (r)") +
  theme_classic()




# Average 2 day jump load
per_athlete_corrs_avg <- load_and_RSI |>
  group_by(anon_id) |>
  summarize(
    r = cor(RSI, `TD-1..Avg..Jump.Load`, use = "complete.obs"),
    n = n()
  ) |>
  arrange(r)

ggplot(per_athlete_corrs_avg, aes(x = reorder(anon_id, r), y = r)) +
  geom_col(fill = "#CFB87C") +
  geom_text(aes(label = round(r, 2)), 
              hjust = ifelse(per_athlete_corrs_avg$r >= 0, -0.1, 1.1),
              size = 3.2,
              color = "#000000") +
  coord_flip() +
  labs(title = "Per Athlete Correlation Between Avg 2-Day Jump Load and RSI",
       x = "Athlete",
       y = "Correlation (r)") +
  theme_classic()



# Total 2 day jump load
per_athlete_corrs_total <- load_and_RSI |>
  group_by(anon_id) |>
  summarize(
    r = cor(RSI, `TD-1..Total..Jump.Load`, use = "complete.obs"),
    n = n()
  ) |>
  arrange(r)

ggplot(per_athlete_corrs_total, aes(x = reorder(anon_id, r), y = r)) +
  geom_col(fill = "#CFB87C") +
  geom_text(aes(label = round(r, 2)), 
              hjust = ifelse(per_athlete_corrs_total$r >= 0, -0.1, 1.1),
              size = 3.2,
              color = "#000000") +
  coord_flip() +
  labs(title = "Per Athlete Correlation Between Total 2-Day Jump Load and RSI",
       x = "Athlete",
       y = "Correlation (r)") +
  theme_classic()


# This allows us to see which athlete's RSI scores are most effected by the prior week's load

set.seed(42)

# Create grouped 5-fold CV splits by anon_id
cv_splits <- group_vfold_cv(load_and_RSI, group = anon_id, v = 5)

# Mixed Effects Model with standardized predictors
cv_mixed <- function(split) {
  train <- training(split)
  test <- testing(split)

  # Manually standardize using training stats
  mean_accel <- mean(train$Last.Week..Avg..Accel.Load, na.rm = TRUE)
  sd_accel   <- sd(train$Last.Week..Avg..Accel.Load, na.rm = TRUE)

  mean_jump  <- mean(train$Last.Week..Avg..Jump.Load, na.rm = TRUE)
  sd_jump    <- sd(train$Last.Week..Avg..Jump.Load, na.rm = TRUE)

  train <- train %>%
    mutate(
      z_avg_accel = (Last.Week..Avg..Accel.Load - mean_accel) / sd_accel,
      z_avg_jump  = (Last.Week..Avg..Jump.Load - mean_jump) / sd_jump
    )

  test <- test %>%
    mutate(
      z_avg_accel = (Last.Week..Avg..Accel.Load - mean_accel) / sd_accel,
      z_avg_jump  = (Last.Week..Avg..Jump.Load - mean_jump) / sd_jump
    )

  model <- lmer(RSI ~ z_avg_accel + z_avg_jump + (1 | anon_id), data = train)
  preds <- predict(model, newdata = test, allow.new.levels = TRUE)

  rmse_vec(truth = test$RSI, estimate = preds)
}

# GAM Model with standardized predictors
cv_gam <- function(split) {
  train <- training(split)
  test <- testing(split)

  # Manually standardize using training stats
  mean_accel <- mean(train$Last.Week..Avg..Accel.Load, na.rm = TRUE)
  sd_accel   <- sd(train$Last.Week..Avg..Accel.Load, na.rm = TRUE)

  mean_jump  <- mean(train$Last.Week..Avg..Jump.Load, na.rm = TRUE)
  sd_jump    <- sd(train$Last.Week..Avg..Jump.Load, na.rm = TRUE)

  train <- train %>%
    mutate(
      z_avg_accel = (Last.Week..Avg..Accel.Load - mean_accel) / sd_accel,
      z_avg_jump  = (Last.Week..Avg..Jump.Load - mean_jump) / sd_jump
    )

  test <- test %>%
    mutate(
      z_avg_accel = (Last.Week..Avg..Accel.Load - mean_accel) / sd_accel,
      z_avg_jump  = (Last.Week..Avg..Jump.Load - mean_jump) / sd_jump
    )

  model <- gam(RSI ~ s(z_avg_accel) + s(z_avg_jump), data = train)
  preds <- predict(model, newdata = test)

  rmse_vec(truth = test$RSI, estimate = preds)
}

# Run CV for both models
mixed_rmses <- map_dbl(cv_splits$splits, cv_mixed)
Warning: Unknown or uninitialised column: `Last.Week..Avg..Accel.Load`.
Warning in mean.default(train$Last.Week..Avg..Accel.Load, na.rm = TRUE) :
  argument is not numeric or logical: returning NA
Warning: Unknown or uninitialised column: `Last.Week..Avg..Accel.Load`.
Warning: Unknown or uninitialised column: `Last.Week..Avg..Jump.Load`.
Warning in mean.default(train$Last.Week..Avg..Jump.Load, na.rm = TRUE) :
  argument is not numeric or logical: returning NA
Warning: Unknown or uninitialised column: `Last.Week..Avg..Jump.Load`.
Error in `map_dbl()`:
ℹ In index: 1.
Caused by error in `mutate()`:
ℹ In argument: `z_avg_accel = (Last.Week..Avg..Accel.Load -
  mean_accel)/sd_accel`.
Caused by error:
! object 'Last.Week..Avg..Accel.Load' not found
Run `]8;;x-r-run:rlang::last_trace()rlang::last_trace()]8;;` to see where the error occurred.
# Fit fixed effects model on full data
avg_fixed_model <- lm(RSI ~ Last.Week..Avg..Accel.Load + Last.Week..Avg..Jump.Load + factor(anon_id),
                  data = load_and_RSI)
Error in eval(predvars, data, env) : 
  object 'Last.Week..Avg..Accel.Load' not found
set.seed(42)

# Create grouped 5-fold CV splits by anon_id
cv_splits <- group_vfold_cv(load_and_RSI, group = anon_id, v = 5)

# Mixed Effects Model with standardized total load predictors
cv_mixed_total <- function(split) {
  train <- training(split)
  test <- testing(split)

  # Manually standardize using training stats
  mean_accel <- mean(train$Last.Week..Total..Accel.Load, na.rm = TRUE)
  sd_accel   <- sd(train$Last.Week..Total..Accel.Load, na.rm = TRUE)

  mean_jump  <- mean(train$Last.Week..Total..Jump.Load, na.rm = TRUE)
  sd_jump    <- sd(train$Last.Week..Total..Jump.Load, na.rm = TRUE)

  train <- train %>%
    mutate(
      z_total_accel = (Last.Week..Total..Accel.Load - mean_accel) / sd_accel,
      z_total_jump  = (Last.Week..Total..Jump.Load - mean_jump) / sd_jump
    )

  test <- test %>%
    mutate(
      z_total_accel = (Last.Week..Total..Accel.Load - mean_accel) / sd_accel,
      z_total_jump  = (Last.Week..Total..Jump.Load - mean_jump) / sd_jump
    )

  model <- lmer(RSI ~ z_total_accel + z_total_jump + (1 | anon_id), data = train)
  preds <- predict(model, newdata = test, allow.new.levels = TRUE)

  rmse_vec(truth = test$RSI, estimate = preds)
}

# GAM Model with standardized total load predictors
cv_gam_total <- function(split) {
  train <- training(split)
  test <- testing(split)

  # Manually standardize using training stats
  mean_accel <- mean(train$Last.Week..Total..Accel.Load, na.rm = TRUE)
  sd_accel   <- sd(train$Last.Week..Total..Accel.Load, na.rm = TRUE)

  mean_jump  <- mean(train$Last.Week..Total..Jump.Load, na.rm = TRUE)
  sd_jump    <- sd(train$Last.Week..Total..Jump.Load, na.rm = TRUE)

  train <- train %>%
    mutate(
      z_total_accel = (Last.Week..Total..Accel.Load - mean_accel) / sd_accel,
      z_total_jump  = (Last.Week..Total..Jump.Load - mean_jump) / sd_jump
    )

  test <- test %>%
    mutate(
      z_total_accel = (Last.Week..Total..Accel.Load - mean_accel) / sd_accel,
      z_total_jump  = (Last.Week..Total..Jump.Load - mean_jump) / sd_jump
    )

  model <- gam(RSI ~ s(z_total_accel) + s(z_total_jump), data = train)
  preds <- predict(model, newdata = test)

  rmse_vec(truth = test$RSI, estimate = preds)
}

# Run CV for both models with total loads
mixed_rmses_total <- map_dbl(cv_splits$splits, cv_mixed_total)
Warning: Unknown or uninitialised column: `Last.Week..Total..Accel.Load`.
Warning in mean.default(train$Last.Week..Total..Accel.Load, na.rm = TRUE) :
  argument is not numeric or logical: returning NA
Warning: Unknown or uninitialised column: `Last.Week..Total..Accel.Load`.
Warning: Unknown or uninitialised column: `Last.Week..Total..Jump.Load`.
Warning in mean.default(train$Last.Week..Total..Jump.Load, na.rm = TRUE) :
  argument is not numeric or logical: returning NA
Warning: Unknown or uninitialised column: `Last.Week..Total..Jump.Load`.
Error in `map_dbl()`:
ℹ In index: 1.
Caused by error in `mutate()`:
ℹ In argument: `z_total_accel = (Last.Week..Total..Accel.Load -
  mean_accel)/sd_accel`.
Caused by error:
! object 'Last.Week..Total..Accel.Load' not found
Run `]8;;x-r-run:rlang::last_trace()rlang::last_trace()]8;;` to see where the error occurred.

Question 4

What is each athlete’s variation in RSI? What is a meaningful change in RSI for the team and for individual athletes?

# Some basic visualizations

VALD_ForceDecks_clean <- VALD_ForceDecks_clean %>%
  filter(Date >= as.Date("2024-09-20", '%Y-%m-%d')) %>%
  filter(!(anon_id %in% c("ID_10", "ID_14", "ID_15", "ID_18", "ID_54", "ID_64")))
  
# Boxplot showing RSI distribution for each athlete
ggplot(VALD_ForceDecks_clean, aes(anon_id, RSI..m.per.s.)) +
  geom_boxplot(color = "#CFB87C") +
  labs(title = "RSI Variability by Athlete") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  theme_classic()



# Line and scatter plot showing RSI trends over time for each athlete
# Includes a black line for the team average RSI to compare individual performance to
ggplot(VALD_ForceDecks_clean, aes(Date, Player.Average.RSI..m.per.s., color = anon_id)) +
  geom_point() + 
  geom_smooth(method = "lm", se=FALSE) +
  labs(title = "Player RSI Over Time with Team Average Line") +
  geom_line(aes(y = Team.Average.RSI..m.per.s.), 
            color = "black") +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

# Smoothed RSI Trend over time
ggplot(load_and_RSI, aes(x = RSI_Date, y = RSI)) +
  geom_smooth(method = "loess", color = "#CFB87C", fill = "#A2A4A3") +
  labs(title = "Smoothed RSI Trend",
       x = "Date",
       y = "RSI Value") +
  theme_classic()
`geom_smooth()` using formula = 'y ~ x'

kendall_cor = cor(VALD_ForceDecks_clean$X, VALD_ForceDecks_clean$Team.Average.RSI..m.per.s., method = "kendall")*-1
ggplot(data=VALD_ForceDecks_clean, aes(x=Date, y=Player.Average.RSI..m.per.s.)) +
  geom_point() +
  geom_smooth(method="lm") +
  labs(title=kendall_cor)
`geom_smooth()` using formula = 'y ~ x'

#taking out all of the IDs in the data set
IDs <- unique(VALD_ForceDecks_clean$anon_id)

#for all unique IDs, calculate Kendall rank correlation, plot player RSI throughout season 
for(i in 1:11){
  RSI <- unique(VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Average.RSI..m.per.s.)
  kendall_cor <- cor(1:length(RSI), RSI, method="kendall")*-1 #calculating Kendall correlation

#plotting each player's RSI throughout the season with their correlation and rough model of the trend
  p <- ggplot(data = VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],], aes(x=Date, y=Player.Average.RSI..m.per.s.)) + 
    geom_point() +
    geom_smooth(method="lm") +
    labs(title = kendall_cor, subtitle = IDs[i])
  
#pring out each plot
  print(p)
}
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'

#for all the players, calculate mean and variance of their RSI measurements and plot
for(i in 1:16){
  #for every player calculate mean and variance using time series assumptions and functions from the time series functions file
  mv <- sample_mean_and_variance(unique(VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Average.RSI..m.per.s.))
  
  #plotting RSI measurements along with calculated mean and 1 standard deviation above and below mean for each player along with their measured RSIs throughout the season
  p <- ggplot(data = VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],], aes(x=Date, y=Player.Average.RSI..m.per.s.)) + 
    geom_point() +
    geom_hline(yintercept = mv[[1]]) +
    geom_hline(yintercept = mv[[1]] + sqrt(mv[[2]]), color="#CFB87C") +
    geom_hline(yintercept = mv[[1]] - sqrt(mv[[2]]), color="#CFB87C") +
    labs(title = "RSI Measurements Throughout Season with Mean and 1 Standard Deviation",subtitle = IDs[i])
  
  #printing out each plot
  print(p)
}

#making empty columns to be filled with indicator variables
VALD_ForceDecks_clean$Player.Above.1.SD <- rep(NA,565)
VALD_ForceDecks_clean$Player.Below.1.SD <- rep(NA,565)
VALD_ForceDecks_clean$Player.Above.2.SD <- rep(NA,565)
VALD_ForceDecks_clean$Player.Below.2.SD <- rep(NA,565)

#for every athlete, checking if a specific RSI measurement is outside 1 standard deviation or 2 calculated for each athlete individually. 
for(i in 1:16){
  #calculating each player's mean and variance with time series function on the time series functions file
  mv <- sample_mean_and_variance(unique(VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Average.RSI..m.per.s.))
  
  #calculating thresholds for 1 and 2 standard deviations away from mean for each player
  sdu1 <- mv[[1]] + sqrt(mv[[2]])
  sdl1 <- mv[[1]] - sqrt(mv[[2]])
  sdu2 <- mv[[1]] + (2*sqrt(mv[[2]]))
  sdl2 <- mv[[1]] - (2*sqrt(mv[[2]]))
  
#checking if RSI value is below 1 standard deviation for each player
  VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Below.1.SD <- ifelse((VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Average.RSI..m.per.s.<sdl1), 1, 0)
  
#checking if RSI value is above 1 standard deviation for each player
  VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Above.1.SD <- ifelse((VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Average.RSI..m.per.s.>sdu1), 1, 0)
  
#checking if RSI value is below 2 standard deviations for each player
  VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Below.2.SD <- ifelse((VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Average.RSI..m.per.s.<sdl2), 1, 0)
  
#checking if RSI value is above 2 standard deviations for each player
  VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Above.2.SD <- ifelse((VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Average.RSI..m.per.s.>sdu2), 1, 0)
}
#making a plot to show potentially significant RSI measurements throughout the season
#dark green means point is above 1 standard deviation from mean
#light green means point is above 2 standard deviations from mean
#dark red means point is below 1 standard deviation from mean
#light red means point is below 2 standard deviations from mean
ggplot(data=VALD_ForceDecks_clean, aes(x=Date, Player.Average.RSI..m.per.s.)) +
  geom_point(color = ifelse(VALD_ForceDecks_clean$Player.Above.2.SD == 1, "palegreen", ifelse(VALD_ForceDecks_clean$Player.Below.2.SD == 1, "red", ifelse(VALD_ForceDecks_clean$Player.Below.1.SD == 1, "red4", ifelse(VALD_ForceDecks_clean$Player.Above.1.SD == 1, "palegreen4", "grey80")))), alpha = 0.4) +
  labs(title = "Significant RSI Measurements Throughout the Season") +
  theme_minimal()

This plot shows each player’s measured RSI throughout the season. Points that are colored gray are points where the player did not have a significant difference in their RSI from their mean RSI throughout the season. Dark green dots show RSI measurements that are above 1 standard deviation for each player and light green dots are RSI measurements that are above 2 standard deviations for each player. Along the same lines, dark red dots shown points in which the player had an RSI below 1 standard deviation from their RSI distribution and light red dots show points in which the player’s measured RSI is below 2 standard deviations of their RSI distribution. One interesting thing about this plot is that there are no measurements that are below even 1 standard deviation for any player after February starts. If anything, there seems to be a higher concentration of RSI measurements that are at least above 1 standard deviation from the mean in the last 5 measurements of the season, after February starts than in the rest of the season. This plot though, does not help us understand how players relate to each other. This chart along with the box plots of each player’s RSI measurements support the conclusion that each player has a very unique RSI distribution. The plot above gets broken down by each player below.

#cycling through all of the players and plotting their RSI measurements throughout the season
for(i in 1:11){
  #plot the measured RSI for each player throughout the season
  #dark green means point is above 1 standard deviation from mean
#light green means point is above 2 standard deviations from mean
#dark red means point is below 1 standard deviation from mean
#light red means point is below 2 standard deviations from mean
p <- ggplot(data=VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],], aes(x=Date, Player.Average.RSI..m.per.s.)) +
  geom_point(color = ifelse(VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Above.2.SD == 1, "palegreen", ifelse(VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Below.2.SD == 1, "red", ifelse(VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Below.1.SD == 1, "red4", ifelse(VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id == IDs[i],]$Player.Above.1.SD == 1, "palegreen4", "grey70"))))) +
  ylim(0.7311404, 2.963925) +
  labs(title = "Measured RSI Values Throughout the Season and Their Significance", subtitle = IDs[i]) +
  theme_minimal()

print(p)
}

The plots above help us to see that the RSI distributions for each player are going to be wildly different from each other. In fact, some of the plots have no overlap with each other (e.g. ID_5 and ID_74). This suggests that defining one singular threshold for what is a meaningful change in RSI will not be accurate for all of the players. These plots when looked at all together also help us to see that when players have an RSI measurement that is below one standard deviation from their mean, it is usually associated with another measurement that is below one standard deviation either directly or in the following two or three measurements before returning to a measurement that is close to their season mean. This is not true for all players but seems to be true for most of the players. This suggests that for most of the team the recovery time for neuromuscular fatigue that results in a noticeably lower RSI score, might be around 8 to 10 days given that RSI measurements are taken every 4 to 5 days on average.

VALD_ForceDecks_clean <- VALD_ForceDecks_clean %>%
  group_by(Date) %>%
  #making 4 new columns that will count how many players were in each category for each date
  mutate(Num.Above.1SD = round(mean(Player.Above.1.SD)*length(unique(anon_id))),
         Num.Below.1SD = round(mean(Player.Below.1.SD)*length(unique(anon_id))),
         Num.Above.2SD = round(mean(Player.Above.2.SD)*length(unique(anon_id))),
         Num.Below.2SD = round(mean(Player.Below.2.SD)*length(unique(anon_id)))) %>%
  ungroup()
Dates <- unique(VALD_ForceDecks_clean$Date)
rows <- rep(NA, 22)

for(i in 1:22){
  rows[i] <- min(VALD_ForceDecks_clean[VALD_ForceDecks_clean$Date == Dates[i],]$X)
}

test <- VALD_ForceDecks_clean[VALD_ForceDecks_clean$X %in% rows,]

ggplot(data=test, aes(x=Date)) +
  geom_col(aes(y=Num.Above.1SD), fill = "palegreen4") +
  geom_col(aes(y=Num.Above.2SD), fill = "palegreen") +
  ylim(0,7) +
  labs(title = "Number of Players Above Their Mean Season RSI Measurement",
       y="Number Above Mean RSI Measurement") +
  theme_minimal()


ggplot(data=test, aes(x=Date)) +
  geom_col(aes(y=Num.Below.1SD), fill = "red4") +
  geom_col(aes(y=Num.Below.2SD), fill = "red") +
  ylim(0,7)+
  labs(title = "Number of Players Below Their Mean Season RSI Measurement",
       y="Number Below Mean RSI Measurement") +
  theme_minimal()

From the plots above, we can see that there are two general parts of the season in which the team has more frequent drops in RSI and the team has more frequent gains in RSI. These plots make it easy to see that the team had a lot more frequent drops in RSI in the beginning of the season than at the end of the season. In fact, the last major drop for any player on the team happened at the end of January and there are no more drops for the rest of the season. With this, we see that RSI gains are not as common throughout the beginning of the season. We only see one or two players that have an RSI measurement above one or two standard deviations above their mean until February. It is only once February starts that we see an increase in the number of players that have an RSI at least one standard deviation above their mean.

Looking at player average RSI values

#calculating the mean and variance of RSI for the players throughout the season
team_mean <- mean(VALD_ForceDecks_clean$Player.Average.RSI..m.per.s.)
team_var <- sample_mean_and_variance(VALD_ForceDecks_clean$Player.Average.RSI..m.per.s.)[[2]]

#plotting RSI measurements throughout the season, adding in the mean RSI value and 1 standard deviation above and below the mean
ggplot(VALD_ForceDecks_clean, aes(x=Date, y=Player.Average.RSI..m.per.s.)) +
  geom_point() +
  geom_hline(yintercept = team_mean) +
  geom_hline(yintercept = team_mean - sqrt(team_var), color="#CFB87C") +
  geom_hline(yintercept = team_mean + sqrt(team_var), color="#CFB87C")

#plotting the RSI values throughout the season and plotting the team RSI trend overtop to see if there are underying trends that could be explained with the team trend
ggplot(VALD_ForceDecks_clean, aes(x=Date, y=Player.Average.RSI..m.per.s.)) +
  geom_point() +
  geom_line(data=VALD_ForceDecks_clean, aes(Date,Team.Average.RSI..m.per.s.), color = "#CFB87C")

#cycle through all of the players
for(i in 1:11){
  #making a plot with date on x axis and average 7 day jump load on the y axis to see if there is potentially any relationship in the trend of the load and changes in RSI
r <- ggplot(rolling_NDay_load[rolling_NDay_load$anon_id == IDs[i],], aes(x=Date, y=Total..7Day..Jump.Load)) +
  geom_point() +
  ylim(0, 400000) +
  labs(title="Jump Loads through the Season", subtitle = IDs[i]) +
  #calculating a moving average to better see the underlying shape of the data
  geom_line(y=moving_average(rolling_NDay_load[rolling_NDay_load$anon_id == IDs[i],]$Total..7Day..Jump.Load,3),
            color = "#CFB87C") +
  
  #adding in vertical lines that represent the dates in which the player had an RSI measurement above or below their mean by at least 1 SD. Same color palette applies
  geom_vline(xintercept = VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id==IDs[i] & VALD_ForceDecks_clean$Player.Above.1.SD==1,]$Date, color = "palegreen4") +
  geom_vline(xintercept = VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id==IDs[i] & VALD_ForceDecks_clean$Player.Above.2.SD==1,]$Date, color = "palegreen") + 
  geom_vline(xintercept = VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id==IDs[i] & VALD_ForceDecks_clean$Player.Below.1.SD==1,]$Date, color = "red4") +
  geom_vline(xintercept = VALD_ForceDecks_clean[VALD_ForceDecks_clean$anon_id==IDs[i] & VALD_ForceDecks_clean$Player.Below.2.SD==1,]$Date, color = "red") +
  geom_hline(yintercept = mean(rolling_NDay_load[rolling_NDay_load$anon_id == IDs[i],]$Total..7Day..Jump.Load))

print(r)
}

Looking at the plots above, there does not seem to be a clear relationship between RSI measurements and loading summarized by any length (2,3,7 days). This suggests that there may have been some other change in training that had a positive impact on RSI measurements for the entire team. This may be due to something that is not loading related. Blake said it might be more targeted lifts.

LS0tDQp0aXRsZTogIkRhdGEgQW5hbHlzaXMgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCiNBdXRob3JzOiBJYW4gTWNFbHZlZW4gYW5kIENlY2lsaWEgR29uemFsZXMNCiNBdXRob3IgRGF0ZTogNi85LzI1DQoNCiNQdXJwb3NlOiBUaGUgcHVycG9zZSBvZiB0aGlzIG5vdGVib29rIGlzIHRvIGhvdXNlIGFsbCBkYXRhIHNldCB0cmFuc2Zvcm1hdGlvbiwgY2xlYW5zaW5nLCB2aXN1YWxpemF0aW9uLCBzdGF0aXN0aWNhbCBhbmFseXNpcywgYW5kIG5vdGUtdGFraW5nIGZvciB0aGUgMjAyNSBDVSBBdGhsZXRpYyBEZXBhcnRtZW50IFNwb3J0cyBTY2llbmNlIEludGVybnNoaXAgUHJvZ3JhbQ0KDQojTEFTVCBVUERBVEVEOiA2LzEyLzIwMjUNCg0KI0luY2x1ZGluZyBoZWxwZnVsIGxpYnJhcmllcw0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkoYW9kKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShib290KQ0KbGlicmFyeShST0NSKQ0KbGlicmFyeShwdXJycikNCmxpYnJhcnkoZ2dmb3JjZSkNCmxpYnJhcnkobG1lNCkNCmxpYnJhcnkoY3YpDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShyc2FtcGxlKQ0KbGlicmFyeSh5YXJkc3RpY2spDQpsaWJyYXJ5KGtuaXRyKQ0KDQoNCiNFeGFtcGxlIG9mIGltcG9ydGluZyBvdXIgZmlyc3QgZGF0YSBzZXQgZnJvbSBhIENTViBmaWxlIHRvIGEgZGF0YSBmcmFtZS4NCg0KIyBkZiA8LSByZWFkLmNzdigiLi9mb28vYmFyLmNzdiIpDQpgYGANCg0KYGBge3IgbG9hZCBpbiBkYXRhc2V0c30NCiNMb2FkIGluIE1CQiAtIFN0YXRpc3RpYyBUcmFja2luZyBSZXBvcnQgY3N2DQpzdGF0cyA8LSByZWFkLmNzdigiZGF0YS1zZXRzL2RhdGEtc2V0cy11bmNvbXByZXNzZWQvZGF0YS1zZXRzLWNvbXByZXNzZWQvUmVhY3RpdmUgU3RyZW5ndGggSW5kZXgvTUJCIC0gU3RhdGlzdGljIFRyYWNraW5nIFJlcG9ydC5jc3YiKQ0KDQojIExvYWQgaW4gQUNXUiAtIEtpbmV4b24gTUJCDQpraW5leG9uX0FDV1IgPC0gcmVhZC5jc3YoImRhdGEtc2V0cy9kYXRhLXNldHMtdW5jb21wcmVzc2VkL2RhdGEtc2V0cy1jb21wcmVzc2VkL1JlYWN0aXZlIFN0cmVuZ3RoIEluZGV4L0FDV1IgLSBLaW5leG9uIE1CQi5jc3YiKQ0KDQojTG9hZGluZyBpbiBWQUxEIC0gRHluYW1vIE1CQg0KVkFMRF9keW5hbW8gPC0gcmVhZC5jc3YoImRhdGEtc2V0cy9kYXRhLXNldHMtdW5jb21wcmVzc2VkL2RhdGEtc2V0cy1jb21wcmVzc2VkL1JlYWN0aXZlIFN0cmVuZ3RoIEluZGV4L1ZBTEQgLSBEeW5hbW8gTUJCLmNzdiIpDQoNCiMgTG9hZCBpbiBWQUxEIC0gRm9yY2VEZWNrcyBNQkIgY3N2DQpWQUxEX0ZvcmNlRGVja3MgPC0gcmVhZC5jc3YoImRhdGEtc2V0cy9kYXRhLXNldHMtdW5jb21wcmVzc2VkL2RhdGEtc2V0cy1jb21wcmVzc2VkL1JlYWN0aXZlIFN0cmVuZ3RoIEluZGV4L1ZBTEQgLSBGb3JjZURlY2tzIE1CQi5jc3YiKQ0KDQojIExvYWQgaW4gS2luZXhvbiBTZXNzaW9uDQpraW5leG9uX3Nlc3Npb24gPC0gcmVhZC5jc3YoImRhdGEtc2V0cy9kYXRhLXNldHMtdW5jb21wcmVzc2VkL2RhdGEtc2V0cy1jb21wcmVzc2VkL1JlYWN0aXZlIFN0cmVuZ3RoIEluZGV4L0tpbmV4b24gU2Vzc2lvbiBNQkIuY3N2IikNCmBgYA0KDQoNCiMjIERhdGEgQ2xlYW5pbmcNCg0KDQpgYGB7ciBjbGVhbiBzdGF0cyBkYXRhc2V0fQ0KIyBSZW1vdmUgY29sdW1ucyB3aGVyZSBhbGwgZGF0YSBwb2ludHMgYXJlIE5BDQpzdGF0c19jbGVhbiA8LSBzdGF0cyB8Pg0KICBzZWxlY3Qod2hlcmUofiAhYWxsKGlzLm5hKC4pKSkpDQoNCg0KIyBJZiBhbGwgdGhyZWUgZGF0ZSBjb2x1bW5zIGFyZSBlcXVhbCwgcmVtb3ZlIHRoZSByZWR1bmRhbnQgb25lcw0KaWYgKGFsbChzdGF0c19jbGVhbiREYXRlID09IHN0YXRzX2NsZWFuJERhdGUuUmV2ZXJzZSwgbmEucm0gPSBUUlVFKSAmJg0KICAgIGFsbChzdGF0c19jbGVhbiREYXRlID09IHN0YXRzX2NsZWFuJFNlc3Npb24uRGF0ZSwgbmEucm0gPSBUUlVFKSkgew0KICANCiAgc3RhdHNfY2xlYW4gPC0gc3RhdHNfY2xlYW4gfD4NCiAgICBzZWxlY3QoLWMoRGF0ZS5SZXZlcnNlLCBTZXNzaW9uLkRhdGUpKQ0KfQ0KDQoNCiMgQ29udmVydCBpZiBEYXRlIGNvbHVtbiBpcyBOT1QgYWxyZWFkeSBpbiBEYXRlIGZvcm1hdA0KaWYgKCFpbmhlcml0cyhzdGF0c19jbGVhbiREYXRlLCAiRGF0ZSIpKSB7DQogIHN0YXRzX2NsZWFuIDwtIHN0YXRzX2NsZWFuICU+JQ0KICAgIG11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAiJW0vJWQvJVkiKSkNCn0NCiMgQ29uZmlybSBpdCdzIG5vdyBpbiBEYXRlIGZvcm1hdA0KY2xhc3Moc3RhdHNfY2xlYW4kRGF0ZSkNCg0Kc3RhdHNfY2xlYW4gPC0gc3RhdHNfY2xlYW5bIWlzLm5hKHN0YXRzX2NsZWFuJFBsdXMuLk1pbnVzKSxdDQoNCiMgQWRkIG1vcmUgc3RhdHMNCnN0YXRzX2NsZWFuIDwtIHN0YXRzX2NsZWFuICU+JQ0KICBmaWx0ZXIoRGF0ZSA+PSBhcy5EYXRlKCIyMDI0LTA5LTIwIiwgJyVZLSVtLSVkJykpICU+JQ0KICBncm91cF9ieShhbm9uX2lkKSAlPiUNCiAgbXV0YXRlKFBsYXllci5BdmVyYWdlLlJlYm91bmRzID0gbWVhbihuYS5vbWl0KFJlYm91bmRzKSksDQogICAgICAgICBQbGF5ZXIuQXZlcmFnZS5TdGVhbHMgPSBtZWFuKG5hLm9taXQoU3RlYWxzKSksDQogICAgICAgICBQbGF5ZXIuQXZlcmFnZS5Bc3Npc3RzID0gbWVhbihuYS5vbWl0KEFzc2lzdHMpKSwNCiAgICAgICAgIFBsYXllci5BdmVyYWdlLlR1cm5vdmVycyA9IG1lYW4obmEub21pdChUdXJub3ZlcnMpKSwNCiAgICAgICAgIFBsYXllci5BdmVyYWdlLlBvaW50cy5TY29yZWQgPSBtZWFuKG5hLm9taXQoUG9pbnRzLlNjb3JlZCkpLA0KICAgICAgICAgUGxheWVyLk1lZGlhbi5SZWJvdW5kcyA9IG1lZGlhbihuYS5vbWl0KFJlYm91bmRzKSksDQogICAgICAgICBQbGF5ZXIuTWVkaWFuLlN0ZWFscyA9IG1lZGlhbihuYS5vbWl0KFN0ZWFscykpLA0KICAgICAgICAgUGxheWVyLk1lZGlhbi5Bc3Npc3RzID0gbWVkaWFuKG5hLm9taXQoQXNzaXN0cykpLA0KICAgICAgICAgUGxheWVyLk1lZGlhbi5UdXJub3ZlcnMgPSBtZWRpYW4obmEub21pdChUdXJub3ZlcnMpKSwNCiAgICAgICAgIFBsYXllci5NZWRpYW4uUG9pbnRzLlNjb3JlZCA9IG1lZGlhbihuYS5vbWl0KFBvaW50cy5TY29yZWQpKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgZ3JvdXBfYnkoRGF0ZSkgJT4lDQogIG11dGF0ZShUZWFtLlJlYm91bmRzID0gc3VtKG5hLm9taXQoUmVib3VuZHMpKSwNCiAgICAgICAgIFRlYW0uU3RlYWxzID0gc3VtKG5hLm9taXQoU3RlYWxzKSksDQogICAgICAgICBUZWFtLkFzc2lzdHMgPSBzdW0obmEub21pdChBc3Npc3RzKSksDQogICAgICAgICBUZWFtLlR1cm5vdmVycyA9IHN1bShuYS5vbWl0KFR1cm5vdmVycykpLA0KICAgICAgICAgVGVhbS5Qb2ludHMuU2NvcmVkID0gYXMubnVtZXJpYyhzdHJfc3BsaXQoR2FtZS5TY29yZSwgIi0iKVtbMV1dWzFdKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgbXV0YXRlKFRlYW0uQXZlcmFnZS5SZWJvdW5kcyA9IG1lYW4oVGVhbS5SZWJvdW5kcyksDQogICAgICAgICBUZWFtLkF2ZXJhZ2UuU3RlYWxzID0gbWVhbihUZWFtLlN0ZWFscyksDQogICAgICAgICBUZWFtLkF2ZXJhZ2UuQXNzaXN0cyA9IG1lYW4oVGVhbS5Bc3Npc3RzKSwNCiAgICAgICAgIFRlYW0uQXZlcmFnZS5UdXJub3ZlcnMgPSBtZWFuKFRlYW0uVHVybm92ZXJzKSwNCiAgICAgICAgIFRlYW0uQXZlcmFnZS5Qb2ludHMuU2NvcmVkID0gbWVhbihUZWFtLlBvaW50cy5TY29yZWQpKSAlPiUNCiAgbXV0YXRlKFBsYXllci5Hb29kLkdhbWUgPSBpZmVsc2UoUmVib3VuZHMgPj0gUGxheWVyLk1lZGlhbi5SZWJvdW5kcyAmIFN0ZWFscyA+PSBQbGF5ZXIuTWVkaWFuLlN0ZWFscyAmIEFzc2lzdHMgPj0gUGxheWVyLk1lZGlhbi5Bc3Npc3RzLDEsMCksDQogICAgICAgICBQbGF5ZXIuQmFkLkdhbWUgPSBpZmVsc2UoUmVib3VuZHMgPCBQbGF5ZXIuTWVkaWFuLlJlYm91bmRzICYgU3RlYWxzIDwgUGxheWVyLk1lZGlhbi5TdGVhbHMgJiBBc3Npc3RzIDwgUGxheWVyLk1lZGlhbi5Bc3Npc3RzLDEsMCksDQogICAgICAgICBUZWFtLkdvb2QuR2FtZSA9IGlmZWxzZShUZWFtLlJlYm91bmRzID49IG1lZGlhbihUZWFtLlJlYm91bmRzKSAmIFRlYW0uU3RlYWxzID49IG1lZGlhbihUZWFtLlN0ZWFscykgJiBUZWFtLkFzc2lzdHMgPj0gbWVkaWFuKFRlYW0uQXNzaXN0cyksMSwwKSwNCiAgICAgICAgIFRlYW0uQmFkLkdhbWUgPSBpZmVsc2UoVGVhbS5SZWJvdW5kcyA8IG1lZGlhbihUZWFtLlJlYm91bmRzKSAmIFRlYW0uU3RlYWxzIDwgbWVkaWFuKFRlYW0uU3RlYWxzKSAmIFRlYW0uQXNzaXN0cyA8IG1lZGlhbihUZWFtLkFzc2lzdHMpLDEsMCkpICU+JQ0KICBzZWxlY3QoLWMoU3BvcnQsIERheS5vZi5XZWVrLCBNb250aCwgTW9udGgud2l0aC5OdW1iZXIsIFllYXIsIE51bWJlci5vZi5Db21wZXRpdGlvbnMuV29uLCBUb3RhbC5EYWlseS5Db21wZXRpdGlvbnMuQXZhaWxhYmxlLCBUb3RhbC5Db21wZXRpdGlvbnMuV29uLCBUb3RhbC5HYW1lLk1pbnV0ZXMsIE9mZmVuc2l2ZS5SZWJvdW5kcywgRGVmZW5zaXZlLlJlYm91bmRzLCBCdWZmLlBsYXlzLCBQZXJjZW50YWdlLkRhaWx5Lm9mLkNvbXBldGl0aW9ucy5Xb24pKSAlPiUNCiAgZmlsdGVyKCEoYW5vbl9pZCAlaW4lIGMoIklEXzEwIiwgIklEXzE0IiwgIklEXzE1IiwgIklEXzE4IiwgIklEXzU0IiwgIklEXzY0IikpKQ0KDQpgYGANCg0KYGBge3IgY2xlYW4ga2luZXhvbl9BQ1dSIGRhdGFzZXR9DQojIFJlbW92ZSBjb2x1bW5zIHdoZXJlIGFsbCBkYXRhIHBvaW50cyBhcmUgTkENCmtpbmV4b25fQUNXUl9jbGVhbiA8LSBraW5leG9uX0FDV1IgfD4NCiAgc2VsZWN0KHdoZXJlKH4gIWFsbChpcy5uYSguKSkpKQ0KDQoNCg0KIyBJZiBhbGwgdGhyZWUgZGF0ZSBjb2x1bW5zIGFyZSBlcXVhbCwgcmVtb3ZlIHRoZSByZWR1bmRhbnQgb25lcw0KaWYgKGFsbChraW5leG9uX0FDV1JfY2xlYW4kRGF0ZSA9PSBraW5leG9uX0FDV1JfY2xlYW4kRGF0ZS5SZXZlcnNlLCBuYS5ybSA9IFRSVUUpICYmDQogICAgYWxsKGtpbmV4b25fQUNXUl9jbGVhbiREYXRlID09IGtpbmV4b25fQUNXUl9jbGVhbiRTZXNzaW9uLkRhdGUsIG5hLnJtID0gVFJVRSkpIHsNCiAgDQogIGtpbmV4b25fQUNXUl9jbGVhbiA8LSBraW5leG9uX0FDV1JfY2xlYW4gfD4NCiAgICBzZWxlY3QoLWMoRGF0ZS5SZXZlcnNlLCBTZXNzaW9uLkRhdGUpKQ0KfQ0KDQoNCiMgQ29udmVydCBpZiBEYXRlIGNvbHVtbiBpcyBOT1QgYWxyZWFkeSBpbiBEYXRlIGZvcm1hdA0KaWYgKCFpbmhlcml0cyhraW5leG9uX0FDV1JfY2xlYW4kRGF0ZSwgIkRhdGUiKSkgew0KICBraW5leG9uX0FDV1JfY2xlYW4gPC0ga2luZXhvbl9BQ1dSX2NsZWFuICU+JQ0KICAgIG11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAiJW0vJWQvJVkiKSkNCn0NCiMgQ29uZmlybSBpdCdzIG5vdyBpbiBEYXRlIGZvcm1hdA0KY2xhc3Moa2luZXhvbl9BQ1dSX2NsZWFuJERhdGUpDQoNCg0KIyBTZWxlY3Rpbmcgb25seSByZWxldmFudCBjb2x1bW5zDQpraW5leG9uX0FDV1JfY2xlYW4gPC0ga2luZXhvbl9BQ1dSX2NsZWFuICU+JQ0KICBzZWxlY3QoYW5vbl9pZCwgRGF0ZSwgRGF5Lm9mLnRoZS5XZWVrLCBNb250aCwgWWVhciwgUG9zaXRpb24sIFNlc3Npb24uVHlwZSwgU2Vzc2lvbi5EZXNjcmlwdGlvbiwgUHJhY3RpY2UuQ2xhc3NpZmljYXRpb24sIExhc3QuNy5EYXkuQWNjZWxlcmF0aW9uLkxvYWQsIFRvZGF5LnMuQWNjZWxlcmF0aW9uLkxvYWQsIEFjY2VsZXJhdGlvbi5Mb2FkLkFDV1IsIEFjY2VsZXJhdGlvbi5Mb2FkLkVXTUEuQUNXUiwgQWN1dGUuVG90YWwuQWNjZWxlcmF0aW9uLkxvYWQsIEFjdXRlLlRvdGFsLkFjY2VsZXJhdGlvbi5Mb2FkLkVXTUEsIENocm9uaWMuVG90YWwuQWNjZWxlcmF0aW9uLkxvYWQsIENocm9uaWMuVG90YWwuQWNjZWxlcmF0aW9uLkxvYWQuRVdNQSwgVG90YWwuTG93LkFjY2VsZXJhdGlvbi5Mb2FkLCBUb3RhbC5NZWRpdW0uQWNjZWxlcmF0aW9uLkxvYWQsIFRvdGFsLkhpZ2guQWNjZWxlcmF0aW9uLkxvYWQsIFRvdGFsLlZlcnkuSGlnaC5BY2NlbGVyYXRpb24uTG9hZCwgTGFzdC43LkRheS5Ub3RhbC5KdW1wLkxvYWQsIFRvZGF5LnMuSnVtcC5Mb2FkLCBUb3RhbC5KdW1wLkxvYWQuQUNXUiwgQWN1dGUuVG90YWwuSnVtcC5Mb2FkLCBBY3V0ZS5Ub3RhbC5KdW1wLkxvYWQuRVdNQSwgQ2hyb25pYy5Ub3RhbC5KdW1wLkxvYWQsIENocm9uaWMuVG90YWwuSnVtcC5Mb2FkLkVXTUEsIExhc3QuNy5EYXkuVG90YWwuTWludXRlcywgVG9kYXkucy5NaW51dGVzLCBNaW51dGVzLkFDV1IsIE1pbnV0ZXMuRVdNQS5BQ1dSLCBBY3V0ZS5NaW51dGVzLCBBY3V0ZS5NaW51dGVzLkVXTUEsIENocm9uaWMuTWludXRlcywgQ2hyb25pYy5NaW51dGVzLkVXTUEsIFRvdGFsLkRpc3RhbmNlLkVXTUEuQUNXUikNCmBgYA0KDQpgYGB7ciBjbGVhbiB0aGUgVkFMRF9keW5hbW8gZGF0YSBzZXR9DQojc2VsZWN0aW5nIGltcG9ydGFudCB2YXJpYWJsZXMsIHJlbW92aW5nIHJvd3Mgd2l0aCBtaXNzaW5nIGRhdGEsIG9ubHkgc2VsZWN0aW5nIGhhbmQgbW92ZW1lbnRzDQpWQUxEX2R5bmFtb19jbGVhbiA8LSBWQUxEX2R5bmFtbyAlPiUNCiAgZmlsdGVyKEJvZHkuUmVnaW9uID09ICJIYW5kIikgJT4lDQogIG11dGF0ZShSaWdodC5TaWRlID0gaWZlbHNlKFJlcGV0aXRpb24uVHlwZS5MYXRlcmFsaXR5PT0iUmlnaHRTaWRlIiwxLDApKSAlPiUNCiAgc2VsZWN0KGFub25faWQsCURhdGUsIE1heC5Gb3JjZS5OZXd0b25zLCBBdmcuRm9yY2UuTmV3dG9ucywgTWF4LkltcHVsc2UuTmV3dG9uLlNlY29uZHMsICBNYXguUmF0ZS5PZi5Gb3JjZS5EZXZlbG9wbWVudC5OZXd0b25zLlBlci5TZWNvbmQsCUF2Zy5SYXRlLk9mLkZvcmNlLkRldmVsb3BtZW50Lk5ld3RvbnMuUGVyLlNlY29uZCwJTWluLlRpbWUuVG8uUGVhay5Gb3JjZS5TZWNvbmRzLCBTdGFydC5PZmZzZXQuU2Vjb25kcywgUmVwZXRpdGlvbi5EdXJhdGlvbi5TZWNvbmRzLAlSZXBldGl0aW9uLk1heC5Gb3JjZS5OZXd0b25zLAlJbXB1bHNlLk5ld3Rvbi5TZWNvbmRzLAlSYXRlLk9mLkZvcmNlLkRldmVsb3BtZW50Lk5ld3RvbnMuUGVyLlNlY29uZCwJVGltZS5Uby5QZWFrLkZvcmNlLlNlY29uZHMsUmlnaHQuU2lkZSkgJT4lDQogIG5hLm9taXQoKQ0KDQojIENvbnZlcnQgaWYgRGF0ZSBjb2x1bW4gaXMgTk9UIGFscmVhZHkgaW4gRGF0ZSBmb3JtYXQNCmlmICghaW5oZXJpdHMoVkFMRF9keW5hbW9fY2xlYW4kRGF0ZSwgIkRhdGUiKSkgew0KICBWQUxEX2R5bmFtb19jbGVhbjwtIFZBTERfZHluYW1vX2NsZWFuJT4lDQogICAgbXV0YXRlKERhdGUgPSBhcy5EYXRlKERhdGUsIGZvcm1hdCA9ICIlbS8lZC8lWSIpKQ0KfQ0KIyBDb25maXJtIGl0J3Mgbm93IGluIERhdGUgZm9ybWF0DQpjbGFzcyhWQUxEX2R5bmFtb19jbGVhbiREYXRlKQ0KDQoNCiNUaGlzIGRhdGEgc2V0IGNvbnRhaW5zIGluZm9ybWF0aW9uIGZyb20gZWFjaCBpbmRpdmlkdWFsIGhhbmQgaW4gYSBzdHJlbmd0aCB0ZXN0IG1lYW5pbmcgdGhhdCB0aGVyZSBhcmUgdHdvIG1lYXN1cmVtZW50cyBwZXIgZGF5IGZvciBlYWNoIHBsYXllci4gVGhpcyBtYWtlcyBpdCBoYXJkIHRvIHVuZGVyc3RhbmQgaW4gcGxvdHMgZXNwZWNpYWxseSB3aGVuIHBsb3R0ZWQgbGlrZSB0aW1lIHNlcmllcyBkYXRhLiBGb3IgZnV0dXJlIHJlZmVyZW5jZSwgaXQgbWlnaHQgYmUgdXNlZnVsIHRvIHRha2UgYW4gYXZlcmFnZSBvZiBib3RoIHNpZGVzIG9yIG5vdGUgdGhhdCB0aGVyZSBpcyBhIGRpZmZlcmVuY2UgaW4gZWFjaCBoYW5kIGFuZCBwbG90IHRoZSBsZWZ0IGFuZCByaWdodHMgc2lkZXMgc2VwYXJhdGVseS4NCg0KIyMjIyBOb3RlIHRoYXQgeW91IGhhdmUgdG8gZ3JvdXAgb24gaWQgYW5kIHRoZSBkYXRlIGluIG9yZGVyIHRvIGdldCBhIHZhbGlkIGF2ZXJhZ2Ugb2YgYm90aCBzaWRlcyBmb3IgYSBzcGVjaWZpYyBkYXkgZm9yIGVhY2ggaW5kaXZpZHVhbCBwbGF5ZXIuIA0KYGBgDQoNCmBgYHtyIGNsZWFuIHRoZSBGb3JjZURlY2tzIGRhdGFzZXR9DQpWQUxEX0ZvcmNlRGVja3NfY2xlYW4gPC0gVkFMRF9Gb3JjZURlY2tzICU+JQ0KICBzZWxlY3Qod2hlcmUofiAhYWxsKGlzLm5hKC4pKSkpICU+JQ0KICBtdXRhdGUoWD0xOjMzODQpICU+JQ0KICBmaWx0ZXIoVGVzdC5UeXBlID09ICJESiIpICU+JQ0KICBzZWxlY3QoWCxhbm9uX2lkLCBEYXRlLCBXZWVrLCBQb3NpdGlvbiwgVGVzdC5UeXBlLCBXZWlnaHQuLmtnLiwgVHJpYWwsIEZsaWdodC5UaW1lLi5zLiwgSnVtcC5IZWlnaHQuLkZsaWdodC5UaW1lLi4uY20uLCBFY2NlbnRyaWMuQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJhdGlvLCBDb250YWN0LlRpbWUuLnMuLCBSU0kuLkpILi5GbGlnaHQuVGltZS4uQ29udGFjdC5UaW1lLiwgUlNJLi5GbGlnaHQuVGltZS5Db250YWN0LlRpbWUuLCBEcm9wLkhlaWdodC4uY20uKSU+JQ0KICBtdXRhdGUoUlNJLi5tLnBlci5zLiA9IChKdW1wLkhlaWdodC4uRmxpZ2h0LlRpbWUuLi5jbS4vMTAwKS9Db250YWN0LlRpbWUuLnMuLA0KICAgICAgICAgRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgJyVtLyVkLyVZJykpICU+JQ0KICBncm91cF9ieShEYXRlLCBhbm9uX2lkKSAlPiUNCiAgbXV0YXRlKFdlaWdodC4ua2cuID0gbWVhbihuYS5vbWl0KFdlaWdodC4ua2cuKSksDQogICAgICAgICBQbGF5ZXIuQXZlcmFnZS5SU0kuLm0ucGVyLnMuID0gbWVhbihSU0kuLm0ucGVyLnMuKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgZ3JvdXBfYnkoRGF0ZSkgJT4lDQogIG11dGF0ZShUZWFtLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLiA9IG1lYW4obmEub21pdChSU0kuLm0ucGVyLnMuKSkpDQpgYGANCg0KYGBge3Iga2luZXhvbiBzZXNzaW9uIG1iYiBjbGVhbmluZ30NCiMgUmVtb3ZlIGNvbHVtbnMgd2hlcmUgYWxsIGRhdGEgcG9pbnRzIGFyZSBOQQ0Ka2luZXhvbl9zZXNzaW9uX2NsZWFuIDwtIGtpbmV4b25fc2Vzc2lvbiB8Pg0KICBzZWxlY3Qod2hlcmUofiAhYWxsKGlzLm5hKC4pKSkpDQoNCg0KIyBDb252ZXJ0IGlmIERhdGUgY29sdW1uIGlzIE5PVCBhbHJlYWR5IGluIERhdGUgZm9ybWF0DQppZiAoIWluaGVyaXRzKGtpbmV4b25fc2Vzc2lvbl9jbGVhbiREYXRlLCAiRGF0ZSIpKSB7DQogIGtpbmV4b25fc2Vzc2lvbl9jbGVhbiA8LSBraW5leG9uX3Nlc3Npb25fY2xlYW4gJT4lDQogICAgbXV0YXRlKERhdGUgPSBhcy5EYXRlKERhdGUsIGZvcm1hdCA9ICIlbS8lZC8lWSIpKQ0KfQ0KIyBDb25maXJtIGl0J3Mgbm93IGluIERhdGUgZm9ybWF0DQpjbGFzcyhraW5leG9uX3Nlc3Npb25fY2xlYW4kRGF0ZSkNCg0KDQojIEZpbHRlciB0byBvbmx5IGluY2x1ZGUgZGF0YSBmcm9tIHRoaXMgc2Vhc29uDQpraW5leG9uX3Nlc3Npb25fY2xlYW4gPC0ga2luZXhvbl9zZXNzaW9uX2NsZWFuIHw+DQogIGZpbHRlcihEYXRlID49IGFzLkRhdGUoIjIwMjQtNi0wMSIpKQ0KYGBgDQoNCg0KIyNBbmFseXNpcw0KDQoNCiMjIFF1ZXN0aW9uIDENCg0KIyMjIEFyZSBjaGFuZ2VzIGluIFJTSSByZWxhdGVkIHRvIHRlYW0gZ2FtZSBwZXJmb3JtYW5jZT8NCg0KIyMjIyBUZWFtIFdpbnMgYW5kIExvc3Nlcw0KDQpgYGB7ciBMb29raW5nIG9ubHkgYXQgbW9zdCByZWNlbnQgc2Vhc29ufQ0KI2ZpbHRlciBGb3JjZURlY2tzIGRhdGEgc2V0IGludG8gb25seSB0aGUgbW9zdCByZWNlbnQgc2Vhc29uIGFuZCBvbmx5IHBsYXllcnMgdGhhdCBwbGF5ZWQgaW4gbW9zdCBvZiB0aGUgZ2FtZXMNCmN1cnJlbnRfc2Vhc29uIDwtIFZBTERfRm9yY2VEZWNrc19jbGVhbiAlPiUNCiAgZmlsdGVyKERhdGUgPj0gYXMuRGF0ZSgiMjAyNC0wOS0yMCIsICclWS0lbS0lZCcpKSAlPiUNCiAgZmlsdGVyKCEoYW5vbl9pZCAlaW4lIGMoIklEXzEwIiwgIklEXzE0IiwgIklEXzE1IiwgIklEXzE4IiwgIklEXzU0IiwgIklEXzY0IikpKQ0KDQojbG9va2luZyBhdCB0aGUgYXZlcmFnZSBSU0kgYXMgd2VsbCBhcyB0aGUgYWRqdXN0ZWQgdmFyaWFuY2UNCiNmdW5jdGlvbnMgdG8gY2FsY3VsYXRlIG1lYW4gYW5kIHZhcmlhbmNlIG9mIHRpbWUgc2VyaWVzIGZvdW5kIGluICJUaW1lLVNlcmllcy1GdW5jdGlvbnMuUm1kIg0KdGVhbV9tZWFuIDwtIG1lYW4oY3VycmVudF9zZWFzb24kVGVhbS5BdmVyYWdlLlJTSS4ubS5wZXIucy4pDQp0ZWFtX3ZhciA8LSBhcy5udW1lcmljKHNhbXBsZV9tZWFuX2FuZF92YXJpYW5jZShjdXJyZW50X3NlYXNvbiRUZWFtLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLilbMl0pDQoNCiNsb29raW5nIGF0IHRoZSB0ZWFtIGF2ZXJhZ2UgUlNJIG92ZXIgdGhlIGNvdXJzZSBvZiB0aGUgc2Vhc29uLCB0aGUgbWlkZGxlIGhvcml6b250YWwgbGluZSByZXByZXNlbnRzIHRoZSBtZWFuIGFuZCB0aGUgZ29sZCBsaW5lcyByZXByZXNlbnQgb25lIHN0YW5kYXJkIGRldmlhdGlvbiBhd2F5IGZyb20gdGhlIG1lYW4NCmdncGxvdChkYXRhID0gY3VycmVudF9zZWFzb24gLGFlcyhEYXRlLCBUZWFtLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLikpICsNCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDAuNzUpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gdGVhbV9tZWFuKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IHRlYW1fbWVhbiArIHNxcnQodGVhbV92YXIpLCBjb2xvcj0iI0NGQjg3QyIpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gdGVhbV9tZWFuIC0gc3FydCh0ZWFtX3ZhciksIGNvbG9yPSIjQ0ZCODdDIikNCg0KI2xvb2tpbmcgYXQgdGhlIGFkanVzdGVkIGNvcnJlbGF0aW9ucyBvZiB0aGUgdGVhbSBhdmVyYWdlcyB0byBzZWUgaWYgdGhlcmUgaXMgYW55IGNvcnJlbGF0aW9uIHdpdGggdGltZQ0KY29yKHggPSBjdXJyZW50X3NlYXNvbiRYLCB5ID0gY3VycmVudF9zZWFzb24kVGVhbS5BdmVyYWdlLlJTSS4ubS5wZXIucy4sIG1ldGhvZCA9ICJrZW5kYWxsIikNCmNvcih4ID0gY3VycmVudF9zZWFzb24kWCwgeSA9IGN1cnJlbnRfc2Vhc29uJFRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuLCBtZXRob2QgPSAic3BlYXJtYW4iKQ0KYGBgDQoNClRoZSBwbG90IGFib3ZlIHNob3dzIHRoZSB0ZWFtJ3MgYXZlcmFnZSBSU0kgcGVyIHdlZWsgdGhyb3VnaG91dCB0aGUgMjAyNC0yMDI1IHNlYXNvbi4gVGhpcyBwbG90IHNob3dzIHRoYXQgdGhlcmUgYXJlIGxhcmdlIHZhcmlhdGlvbnMgaW4gdGVhbSdzIFJTSSB2YWx1ZXMgdGhyb3VnaG91dCB0aGUgc2Vhc29uIGJ1dCB0aGVyZSBkb2VzIG5vdCBzZWVtIHRvIGJlIGFueSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHVuZGVybHlpbmcgdHJlbmQgaW4gdGhlIGRhdGEuIFRoZSBsaW5lcyBpbiB0aGUgcGxvdCByZXByZXNlbnQgdGhlIG1lYW4gYW5kIG9uZSBzdGFuZGFyZCBkZXZpYXRpb24gZnJvbSB0aGUgbWVhbiB0aHJvdWdob3V0IHRoZSBzZWFzb24uIEFzIHlvdSBjYW4gc2VlLCB0aGVyZSBpcyBhIGxvdCBvZiB2YXJpYWJpbGl0eSB0aHJvdWdob3V0IHRoZSBkYXRhLiBUaGUgcGF0dGVybnMgdGhhdCBhcHBlYXIgdGhvdWdoIGNvdWxkIHBvdGVudGlhbGx5IHN1Z2dlc3QgYW4gdW5kZXJseWluZyBBUklNQSBvciBvdGhlciBtb2RlbCBmb3IgdGhlIGRhdGEuDQoNCmBgYHtyIENhbGN1bGF0aW5nIFJTSSBjaGFuZ2VzIHRocm91Z2hvdXQgdGhlIHNlYXNvbn0NCg0KI2NhbGN1bGF0aW5nIG1lYW4gUlNJIHZhbHVlcyBmb3IgZWFjaCBkYXkgYW5kIGF0dGFjaGluZyB0aGVtIHRvIGNvcnJlY3QgZGF0ZXMNClRlYW0ubWVhbnMgPC0gdW5pcXVlKGN1cnJlbnRfc2Vhc29uJFRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuKQ0KRGF0ZXMgPC0gdW5pcXVlKGN1cnJlbnRfc2Vhc29uJERhdGUpDQpJRHMgPC0gdW5pcXVlKGN1cnJlbnRfc2Vhc29uJGFub25faWQpDQpUZWFtLkNoYW5nZSA8LSByZXAoMCwgMjUpDQpjdXJyZW50X3NlYXNvbiRDaGFuZ2UuVGVhbS5BdmVyYWdlLlJTSS4ubS5wZXIucy4gPC0gcmVwKE5BLCA1ODApDQoNCiNjYWxjdWxhdGluZyB0aGUgZGlmZmVyZW5jZSBpbiBSU0kgZnJvbSB0aGUgcHJldmlvdXMgbWVhc3VyZW1lbnQgYW5kIGF0dGFjaGluZyBhcyBhIG5ldyBjb2x1bW4gaW4gdGhlIGN1cnJlbnQgc2Vhc29uIGRhdGEgc2V0DQpmb3IoaSBpbiAyOjI1KXsNCiAgVGVhbS5DaGFuZ2VbaV0gPSBUZWFtLm1lYW5zW2ldIC0gVGVhbS5tZWFuc1tpKzFdDQogIGN1cnJlbnRfc2Vhc29uW2N1cnJlbnRfc2Vhc29uJERhdGUgPT0gRGF0ZXNbaV0sMTldPC0gVGVhbS5DaGFuZ2VbaV0NCn0NCg0KI21ha2luZyBiaW5hcnkgY29sdW1uIG9mIHdoZXRoZXIgUlNJIGluY3JlYXNlZCBvciBub3QNCmN1cnJlbnRfc2Vhc29uIDwtIGN1cnJlbnRfc2Vhc29uICU+JQ0KICBtdXRhdGUoVGVhbS5SU0kuSW5jcmVhc2UgPSBpZmVsc2UoQ2hhbmdlLlRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuID4gMCwgMSwgMCkpDQoNCg0KI2NhbGN1bGF0aW5nIHRoZSBkaWZmZXJlbmNlIGluIFJTSSBmcm9tIHRoZSBwcmV2aW91cyBtZWFzdXJlbWVudCBmb3IgZWFjaCBwbGF5ZXIgYW5kIGF0dGFjaGluZyBhcyBhIG5ldyBjb2x1bW4gaW4gdGhlIGN1cnJlbnQgc2Vhc29uIGRhdGEgc2V0DQpjdXJyZW50X3NlYXNvbiRDaGFuZ2UuUGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLiA8LSByZXAoMCw1ODApICNtYWtpbmcgbmV3IGNvbHVtbg0KDQpmb3IoaSBpbiAxOjExKXsgI2N5Y2xlIHRocm91Z2ggcGxheWVycywgY2FsY3VsYXRlIGRpZmZlcmVuY2UgZnJvbSBsYXN0IG1lYXN1cmVtZW50DQogIERhdGVzIDwtIHVuaXF1ZShjdXJyZW50X3NlYXNvbltjdXJyZW50X3NlYXNvbiRhbm9uX2lkID09IElEc1tpXSxdJERhdGUpDQogIFBsYXllci5NZWFucyA8LSB1bmlxdWUoY3VycmVudF9zZWFzb25bY3VycmVudF9zZWFzb24kYW5vbl9pZCA9PSBJRHNbaV0sXSRQbGF5ZXIuQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSAjdGFraW5nIG1lYXN1cmVtZW50cyB0aHJvdWdob3V0IHNlYXNvbg0KICBQbGF5ZXIuQ2hhbmdlIDwtIHJlcCgwLGxlbmd0aChQbGF5ZXIuTWVhbnMpKQ0KICBpZmVsc2UoaSAhPSAxNCwgUGxheWVyLkNoYW5nZSA8LSByZXAoMCxsZW5ndGgoUGxheWVyLk1lYW5zKSksIDApICNkb24ndCBuZWVkIHRoaXMgbGluZSBhbnkgbW9yZSBidXQgSSBhbSBub3QgZ29pbmcgdG8gZGVsZXRlIGl0DQoNCiAgZm9yKGogaW4gMTpsZW5ndGgoUGxheWVyLkNoYW5nZSkpeyAjY2FsY3VsYXRlcyBjaGFuZ2VzIGZyb20gbGFzdCBtZWFzdXJlbWVudHMNCiAgICBQbGF5ZXIuQ2hhbmdlW2pdIDwtIFBsYXllci5NZWFuc1tqXSAtIFBsYXllci5NZWFuc1tqKzFdDQogICAgfQ0KICAjYXR0YWNoaW5nIFJTSSBjaGFuZ2VzIGluIG5ldyBjb2x1bW4gIA0KICBmb3IoayBpbiAxOmxlbmd0aChQbGF5ZXIuQ2hhbmdlKSl7DQogICAgY3VycmVudF9zZWFzb25bY3VycmVudF9zZWFzb24kRGF0ZSA9PSBEYXRlc1trXSAmIGN1cnJlbnRfc2Vhc29uJGFub25faWQgPT0gSURzW2ldLF0kQ2hhbmdlLlBsYXllci5BdmVyYWdlLlJTSS4ubS5wZXIucy4gPSBQbGF5ZXIuQ2hhbmdlW2tdDQogIH0NCn0NCg0KI21ha2luZyBpbmRpY2F0b3IgdmFyaWFibGUgZm9yIHdoZXRoZXIgUlNJIGluY3JlYXNlZCBmcm9tIGxhc3QgbWVhc3VyZW1lbnQgb3Igbm90DQpjdXJyZW50X3NlYXNvbiA8LSBjdXJyZW50X3NlYXNvbiAlPiUNCiAgbXV0YXRlKFBsYXllci5SU0kuSW5jcmVhc2UgPSBpZmVsc2UoQ2hhbmdlLlBsYXllci5BdmVyYWdlLlJTSS4ubS5wZXIucy4gPiAwLCAxLCAwKSkNCmBgYA0KDQojIyMjIyMgTWF5YmUgRGVsZXRlDQpgYGB7ciBEYXRhc2V0IGZvciBzZWFzb24gd2lucyBhbmQgbG9zc2VzfQ0KI3JlcHJlc2VudHMgZ2FtZXMgdGhyb3VnaG91dCB0aGUgc2Vhc29uLCB3aWxsIG1lcmdlIGludG8gb25lIGRhdGEgc2V0DQpXaW4gPC0gYygxLDEsMSwxLDEsMCwxLDAsMSwxLDEsMSwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDEsMCwxLDAsMCwwLDEsMSwxLDAsMCkNCkFsbF9EYXRlcyA8LSBhcy5EYXRlKGMoIjIwMjQtMTAtMTkiLCIyMDI0LTExLTQiLCAiMjAyNC0xMS04IiwgIjIwMjQtMTEtMTMiLCAiMjAyNC0xMS0xNyIsICIyMDI0LTExLTI1IiwiMjAyNC0xMS0yNiIsICIyMDI0LTExLTI3IiwgIjIwMjQtMTItMiIsICIyMDI0LTEyLTciLCAiMjAyNC0xMi0xMyIsICIyMDI0LTEyLTIxIiwgIjIwMjQtMTItMzAiLCAiMjAyNS0xLTQiLCAiMjAyNS0xLTgiLCAiMjAyNS0xLTEyIiwgIjIwMjUtMS0xNSIsICIyMDI1LTEtMTgiLCAiMjAyNS0xLTIxIiwgIjIwMjUtMS0yNSIsICIyMDI1LTEtMjgiLCAiMjAyNS0yLTIiLCAiMjAyNS0yLTUiLCAiMjAyNS0yLTgiLCAiMjAyNS0yLTExIiwgIjIwMjUtMi0xNSIsICIyMDI1LTItMTgiLCAiMjAyNS0yLTIyIiwgIjIwMjUtMi0yNCIsICIyMDI1LTMtMiIsICIyMDI1LTMtNSIsICIyMDI1LTMtOCIsICIyMDI1LTMtMTEiLCIyMDI1LTMtMTIiLCAiMjAyNS0zLTEzIiwgIjIwMjUtNC0xIiksIiVZLSVtLSVkIikNClJlZ3VsYXIgPC0gYXMuRGF0ZShjKCIyMDI0LTEwLTE5IiwiMjAyNC0xMS00IiwgIjIwMjQtMTEtOCIsICIyMDI0LTExLTEzIiwgIjIwMjQtMTEtMTciLCAiMjAyNC0xMi0yIiwgIjIwMjQtMTItNyIsICIyMDI0LTEyLTEzIiwgIjIwMjQtMTItMjEiLCAiMjAyNC0xMi0zMCIsICIyMDI1LTEtNCIsICIyMDI1LTEtOCIsICIyMDI1LTEtMTIiLCAiMjAyNS0xLTE1IiwgIjIwMjUtMS0xOCIsICIyMDI1LTEtMjEiLCAiMjAyNS0xLTI1IiwgIjIwMjUtMS0yOCIsICIyMDI1LTItMiIsICIyMDI1LTItNSIsICIyMDI1LTItOCIsICIyMDI1LTItMTEiLCAiMjAyNS0yLTE1IiwgIjIwMjUtMi0xOCIsICIyMDI1LTItMjIiLCAiMjAyNS0yLTI0IiwgIjIwMjUtMy0yIiwgIjIwMjUtMy01IiwgIjIwMjUtMy04IiksIiVZLSVtLSVkIikNClRvdXJuYW1lbnQgPC0gYXMuRGF0ZShjKCIyMDI0LTExLTI1IiwiMjAyNC0xMS0yNiIsICIyMDI0LTExLTI3IiksIiVZLSVtLSVkIikNClBvc3RfU2Vhc29uIDwtIGFzLkRhdGUoYygiMjAyNS0zLTExIiwiMjAyNS0zLTEyIiwgIjIwMjUtMy0xMyIsICIyMDI1LTQtMSIpLCIlWS0lbS0lZCIpDQoNCiNzdW1tYXJpemVzIGFsbCBnYW1lcyB0aHJvdWdob3V0IHRoZSBzZWFzb24NCnJlY29yZCA8LSBkYXRhLmZyYW1lKERhdGUgPSBBbGxfRGF0ZXMsIFdpbiA9IFdpbikgJT4lDQogIG11dGF0ZShUeXBlID0gY2FzZV93aGVuKA0KICAgIERhdGUgJWluJSBSZWd1bGFyIH4gIlJlZ3VsYXIiLA0KICAgIERhdGUgJWluJSBUb3VybmFtZW50IH4gIlRvdXJuYW1lbnQiLA0KICAgIERhdGUgJWluJSBQb3N0X1NlYXNvbiB+ICJQb3N0LVNlYXNvbiIsDQogICAgVFJVRSB+ICJOQSINCiAgKSkNCmBgYA0KDQpgYGB7ciBQbG90dGluZyBnYW1lIG91dGNvbWVzIHRocm91Z2hvdXQgdGhlIHNlYXNvbiB3aXRoIGF2ZXJhZ2UgdGVhbSBSU0l9DQojcGxvdHRpbmcgcmVndWxhciBnYW1lIG91dGNvbWVzIGFnYWluc3QgUlNJIHZhbHVlcw0KZ2dwbG90KGN1cnJlbnRfc2Vhc29uLCBhZXMoRGF0ZSwgVGVhbS5BdmVyYWdlLlJTSS4ubS5wZXIucy4pKSArDQogIGdlb21fbGluZShsaW5ld2lkdGggPSAwLjc1KSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHJlY29yZCREYXRlW3JlY29yZCRUeXBlID09ICJSZWd1bGFyIl0sIGxpbmV3aWR0aCA9IDAuMiwgY29sb3IgPSBpZmVsc2UocmVjb3JkJFdpbltyZWNvcmQkVHlwZSA9PSAiUmVndWxhciJdID09IDEsICJwYWxlZ3JlZW4zIiwgInJlZDMiKSkNCg0KI3Bsb3R0aW5nIHRvdXJuYW1lbnRzIG9yIHBvc3Qgc2Vhc29uIGdhbWVzIHdpdGggYXZlcmFnZSB0ZWFtIFJTSSB2YWx1ZXMNCmdncGxvdChjdXJyZW50X3NlYXNvbiwgYWVzKERhdGUsIFRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSkgKw0KICBnZW9tX2xpbmUobGluZXdpZHRoID0gMC43NSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSByZWNvcmQkRGF0ZVtyZWNvcmQkVHlwZSAlaW4lIGMoIlRvdXJuYW1lbnQiLCJQb3N0LVNlYXNvbiIpXSwgbGluZXdpZHRoID0gMC4yLCBjb2xvciA9IGlmZWxzZShyZWNvcmQkV2luW3JlY29yZCRUeXBlICVpbiUgYygiVG91cm5hbWVudCIsICJQb3N0LVNlYXNvbiIpXSA9PSAxLCAicGFsZWdyZWVuMyIsICJyZWQzIikpDQpgYGANCg0KVGhlc2UgcGxvdHMgc2hvdyB0aGF0IHRoZXJlIG1heSBub3QgYmUgbXVjaCBwcmVkaWN0aXZlIHBvd2VyIGZvciB0ZWFtIGdhbWUgcGVyZm9ybWFuY2UgZnJvbSB0ZWFtIFJTSSB2YWx1ZXMgdGhlbXNlbHZlcy4gSW5zdGVhZCwgaXQgbWF5IGJlIHVzZWZ1bCB0byBsb29rIGF0IHRoZSBjaGFuZ2VzIGluIFJTSSBiZWZvcmUgZWFjaCBnYW1lIG9yIGxvb2sgYXQgYSBub3JtYWxpemVkIHBsb3Qgb2YgdGhlIHRlYW0ncyBhdmVyYWdlIFJTSSB0byBnZXQgYSBsb29rIGF0IHdoYXQgaXQgd291bGQgbG9vayBsaWtlIHdpdGhvdXQgYXMgbXVjaCBub2lzZS4NCg0KVGhlIGRhdGEgd2FzIG5vcm1hbGl6ZWQgd2l0aCBhIG1vdmluZyBhdmVyYWdlIHByb2Nlc3Mgd2hpY2ggcmVtb3ZlZCBzb21lIG9mIHRoZSBub2lzZSBwcmVzZW50IGluIHRoZSBkYXRhLiBGb3IgdGhpcyBwbG90LCB0aGUgZ3JlZW4gbGluZXMgcmVwcmVzZW50IGEgZ2FtZSBpbiB3aGljaCB0aGUgdGVhbSdzIHN0YXRzIHdlcmUgaGlnaGVyIHRoYW4gdGhlIG1lZGlhbiBmb3Igc3RlYWxzLCBhc3Npc3RzLCBhbmQgcmVib3VuZHMuIFJlZCBsaW5lcyByZXByZXNlbnQgZ2FtZXMgd2hlcmUgdGhlIHRvdGFsIHRlYW0gc3VtIG9mIHN0ZWFscywgYXNzaXN0cywgYW5kIHJlYm91bmRzIGFyZSBsb3dlciB0aGFuIHRoZSBzZWFzb24gbWVkaWFuLiBBZ2FpbiwgVGhlcmUgZG9lcyBub3Qgc2VlbSB0byBiZSBhIGxvZ2ljYWwgYXNzb2NpYXRpb24gYmV0d2VlbiB0ZWFtIGF2ZXJhZ2UgUlNJIGFuZCBpbiBnYW1lIHN0YXRpc3RpY3MuIEluc3RlYWQsIHdlIGZpbmQgdGhhdCBnYW1lcyB0aGF0IGhhZCBiZXR0ZXIgaW4gZ2FtZSBwZXJmb3JtYW5jZSBhcmUgYXNzb2NpYXRlZCB3aXRoIGxvd2VyIFJTSSByZWNvcmRpbmdzIGJlZm9yZSB0aGUgZ2FtZSBhbmQgZ2FtZXMgdGhhdCBoYWQgd29yc2UgaW4gZ2FtZSBwZXJmb3JtYW5jZSBhcmUgYXNzb2NpYXRlZCB3aXRoIGhpZ2hlciBSU0kgcmVjb3JkaW5nIGp1c3QgYmVmb3JlIHRoZSBnYW1lLiBJdCdzIGltcG9ydGFudCB0byBub3RlIHRoYXQgdGhlcmUgZ2FwcyBiZXR3ZWVuIG1lYXN1cmVtZW50cyB0aGF0IGNvdWxkIGhhdmUgbWlzc2VkIGltcG9ydGFudCBzcGlrZXMgb3IgZGlwcyBpbiBSU0kgZm9yIHRoZSB0ZWFtIHRoYXQgd291bGQgZ2l2ZSB1cyBhIG1vcmUgY2xlYXIgdW5kZXJzdGFuZGluZyBvZiB0aGUgcmVsYXRpb25zaGlwLiBQcmV2aW91cyByZXNlYXJjaCB0aGF0IHdhcyBhYmxlIHRvIGlkZW50aWZ5IHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBpbiBnYW1lIHBlcmZvcm1hbmNlIGFuZCBSU0kgbWVhc3VyZW1lbnRzIHdlcmUgYWJsZSB0byBjb2xsZWN0IGl0IGJlZm9yZSBhbmQgYWZ0ZXIgZWFjaCBldmVudC4NCg0KYGBge3IgUGxvdHRpbmcgdGhlIGNoYW5nZXMgaW4gUlNJIHRocm91Z2hvdXQgdGhlIHNlYXNvbn0NCiNwbG90dGluZyB0aGUgY2hhbmdlIGluIHRlYW0gYXZlcmFnZSBSU0kgdGhyb3VnaG91dCB0aGUgc2Vhc29uDQpnZ3Bsb3QoZGF0YSA9IGN1cnJlbnRfc2Vhc29uLCBhZXMoeD1EYXRlLCB5PUNoYW5nZS5UZWFtLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLikpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkNCg0KDQojcGxvdHRpbmcgdGhlIGNoYW5nZXMgaW4gdGVhbSBhdmVyYWdlIFJTSSB0aHJvdWdob3V0IHRoZSBzZWFzb24gd2l0aCBncmVlbiBnYW1lcyBiZWluZyBnYW1lcyB3aGVyZSB0aGUgdGVhbSBwZXJmb3JtZWQgYmV0dGVyIHRoYW4gdGhlaXIgbWVkaWFuIHBlcmZvcm1hbmNlIGluIGV4cGxvc2l2ZW5lc3MgbWV0cmljcyBhbmQgcmVkIGJlaW5nIGdhbWVzIHdoZXJlIHRoZSB0ZWFtIHBlcmZvcm1lZCBiZWxvdyBtZWRpYW4gZm9yIGV4cGxvc2l2ZW5lc3MgbWV0cmljcw0KZ2dwbG90KGRhdGEgPSBjdXJyZW50X3NlYXNvbiwgYWVzKHg9RGF0ZSwgeT1DaGFuZ2UuVGVhbS5BdmVyYWdlLlJTSS4ubS5wZXIucy4pKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gc3RhdHNfY2xlYW4kRGF0ZVtzdGF0c19jbGVhbiRUZWFtLkdvb2QuR2FtZSA9PTEgfCBzdGF0c19jbGVhbiRUZWFtLkJhZC5HYW1lID09MV0sIGNvbG9yID0gaWZlbHNlKHN0YXRzX2NsZWFuWyhzdGF0c19jbGVhbiRUZWFtLkdvb2QuR2FtZSA9PTEgfCBzdGF0c19jbGVhbiRUZWFtLkJhZC5HYW1lID09MSksXSRUZWFtLkdvb2QuR2FtZSA9PSAxLCAicGFsZWdyZWVuMyIsInJlZDMiKSkNCiMgIGdlb21fdGV4dChkYXRhID0gc3RhdHNfY2xlYW4sIHggPSBEYXRlLCB5ID0gMC4xOSwgbGFiZWwgPSBEYXRlLCBhbmdsZSA9IDkwLHNpemUgPSAyLjc1KQ0KYGBgDQoNClRoaXMgcGxvdCBzaG93cyB0aGUgY2hhbmdlIGluIHRlYW0gYXZlcmFnZSBSU0kgbWVhc3VyZW1lbnRzIHRocm91Z2hvdXQgdGhlIHNlYXNvbi4gRWFjaCBkYXRhIHBvaW50IHJlcHJlc2VudHMgaG93IG11Y2ggdGhlIGF2ZXJhZ2UgUlNJIGNoYW5nZWQgZnJvbSB0aGUgcHJldmlvdXMgbWVhc3VyZW1lbnQuIFRoaXMgcGxvdCBoZWxwcyB0byBtYWtlIHNlbnNlIG9mIGhvdyB0aGUgUlNJIG9mIHRoZSB0ZWFtIGNoYW5nZWQgdGhyb3VnaG91dCB0aGUgc2Vhc29uLiBXZSBjYW4gc2VlIHRoYXQgd2hpbGUgaW5jcmVhc2VzIHdlcmUgbW9yZSBmcmVxdWVudCwgdGhleSB3ZXJlIHNtYWxsZXIgdGhhbiB0aGUgZHJvcHMgaW4gUlNJIHRoYXQgb2NjdXJyZWQgdGhyb3VnaG91dCB0aGUgc2Vhc29uLiBXaXRoIHRoaXMgdGhvdWdoLCB3ZSBjYW4gc2VlIHRoYXQgdGhlcmUgaXMgcG90ZW50aWFsbHkgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiBjaGFuZ2VzIGluIFJTSSBhbmQgaW4gdGVhbSBnYW1lIHBlcmZvcm1hbmNlLiBUaGlzIGlzIGJlY2F1c2UgdmlzdWFsbHksIGl0IHNlZW1zIHRoYXQgZ2FtZXMgd2hlcmUgdGhlIHRlYW0gaGFkIGEgImdvb2QiIGdhbWUgdGVuZCB0byBoYXZlIGFuIGluY3JlYXNlIGluIFJTSSBtZWFzdXJlZCByaWdodCBiZWZvcmUgdGhlIGdhbWUgYW5kIGdhbWVzIHRoYXQgYXJlICJiYWQiIHRlbmQgdG8gaGF2ZSBhIGRlY3JlYXNlIGluIFJTSSByaWdodCBiZWZvcmUgdGhlIGdhbWUgb3IgYSBsZXNzIGRyYW1hdGljIGluY3JlYXNlIGluIFJTSSB0aGFuIGdhbWVzIHRoYXQgYXJlICJnb29kIi4NCg0KIyMjIyMjIE1heWJlIERlbGV0ZQ0KDQpgYGB7ciBwbG90dGluZyB0aGUgY2hhbmdlcyBpbiBSU0kgd2l0aCB3aW5zIGFuZCBsb3NzZXMgdGhyb3VnaG91dCB0aGUgc2Vhc29ufQ0KZ2dwbG90KGRhdGEgPSBjdXJyZW50X3NlYXNvbiwgYWVzKHg9RGF0ZSwgeT1UZWFtLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLikpICsNCiAgZ2VvbV9saW5lKGFlcyhjb2xvciA9IFRlYW0uUlNJLkluY3JlYXNlKSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSByZWNvcmQkRGF0ZVtyZWNvcmQkV2luID09IDFdLCBsaW5ld2lkdGggPSAwLjIsIGNvbG9yID0gInBhbGVncmVlbjMiKQ0KDQpnZ3Bsb3QoZGF0YSA9IGN1cnJlbnRfc2Vhc29uLCBhZXMoeD1EYXRlLCB5PVRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSkgKw0KICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gVGVhbS5SU0kuSW5jcmVhc2UpLCBsaW5ld2lkdGggPSAwLjc1KSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHJlY29yZCREYXRlW3JlY29yZCRXaW4gPT0gMF0sIGxpbmV3aWR0aCA9IDAuMiwgY29sb3IgPSAicmVkMyIpDQpgYGANCg0KDQojIyMjIFRlYW0gRXhwbG9zaXZlbmVzcyBNZXRyaWNzDQoNCmBgYHtyIHBsb3R0aW5nIHRlYW0gc2NvcmVzIGFnYWluc3QgdGhlIHRlYW0gbWVkaWFuIHNjb3JlfQ0KZ2dwbG90KGRhdGEgPSBjdXJyZW50X3NlYXNvbiwgYWVzKERhdGUsIFRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHN0YXRzX2NsZWFuJERhdGUsIGNvbG9yID0gaWZlbHNlKHN0YXRzX2NsZWFuJFRlYW0uUG9pbnRzLlNjb3JlZCA+IG1lZGlhbihzdGF0c19jbGVhbiRUZWFtLlBvaW50cy5TY29yZWQpLCAicGFsZWdyZWVuMyIsICJyZWQzIiksIGxpbmV3aWR0aCA9IDAuMikNCg0KDQpnZ3Bsb3QoZGF0YSA9IGN1cnJlbnRfc2Vhc29uLCBhZXMoeD1EYXRlLCB5PUNoYW5nZS5UZWFtLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLikpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKw0KICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gc3RhdHNfY2xlYW4kRGF0ZSwgY29sb3IgPSBpZmVsc2Uoc3RhdHNfY2xlYW4kVGVhbS5Qb2ludHMuU2NvcmVkID4gbWVkaWFuKHN0YXRzX2NsZWFuJFRlYW0uUG9pbnRzLlNjb3JlZCksICJwYWxlZ3JlZW4zIiwgInJlZDMiKSwgbGluZXdpZHRoID0gMC4yKQ0KYGBgDQoNClRoaXMgcGxvdCByZXByZXNlbnRzIGlmIHRoZSB0ZWFtIHNjb3JlZCBoaWdoZXIgb3IgbG93ZXIgdGhhbiB0aGUgbWVkaWFuIHRlYW0gc2NvcmUgaW4gdGhhdCBnYW1lLiBHcmVlbiByZXByZXNlbnRzIGhpZ2hlciBhbmQgcmVkIHJlcHJlc2VudHMgbG93ZXIgdGhhbiB0aGUgbWVkaWFuLiBUaGlzIHBsb3Qgc3VnZ2VzdHMgdGhhdCBsb3dlciB0aGFuIG1lZGlhbiBzY29yZXMgYXJlIGFzc29jaWF0ZWQgd2l0aCBkcm9wcyBpbiBSU0kgYmVmb3JlIHRoZSBnYW1lIChmb3VuZCBpbiB0aGUgbWlkZGxlIG9mIHRoZSBzZWFzb24pLiBBcyB0aGUgc2Vhc29uIGdvZXMgb24sIHdlIGNhbiBzZWUgdGhhdCBldmVuIHRob3VnaCB0aGUgdGVhbSdzIFJTSSBnb2VzIHVwLCB0aGUgdGVhbSBoYXMgYSBjb25zaXN0ZW50bHkgbG93ZXIgdGhhbiBtZWRpYW4gc2NvcmUuIFRoaXMgY291bGQgYmUgaW5kaWNhdGl2ZSBvZiB0cm91YmxlIHJlY292ZXJpbmcgZnJvbSBmYXRpZ3VlIGZvdW5kIGluIGVhcmxpZXIgcmVzZWFyY2guDQoNCmBgYHtyIExvb2tpbmcgYXQgdGVhbSBzdW1tYXJ5IHN0YXRpc3RpY3MgY29tcGFyZWQgdG8gbWVkaWFuIHdpdGggUlNJIHZhbHVlcyB0aHJvdWdob3V0IHRoZSBzZWFzb259DQojTG9va2luZyBhdCBnYW1lcyB0aGF0IGhhZCB0ZWFtIHRvdGFsIHJlYm91bmRzIGFib3ZlIG9yIGJlbG93IG1lZGlhbiB0ZWFtIHNlYXNvbiB2YWx1ZQ0KZ2dwbG90KGRhdGEgPSBjdXJyZW50X3NlYXNvbiwgYWVzKERhdGUsIFRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHN0YXRzX2NsZWFuJERhdGUsIGNvbG9yID0gaWZlbHNlKHN0YXRzX2NsZWFuJFRlYW0uUmVib3VuZHMgPiBtZWRpYW4oc3RhdHNfY2xlYW4kVGVhbS5SZWJvdW5kcyksICJwYWxlZ3JlZW4zIiwgInJlZDMiKSwgbGluZXdpZHRoID0gMC4yKQ0KDQpnZ3Bsb3QoZGF0YSA9IGN1cnJlbnRfc2Vhc29uLCBhZXMoeD1EYXRlLCB5PUNoYW5nZS5UZWFtLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLikpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gc3RhdHNfY2xlYW4kRGF0ZSwgY29sb3IgPSBpZmVsc2Uoc3RhdHNfY2xlYW4kVGVhbS5SZWJvdW5kcyA+IG1lZGlhbihzdGF0c19jbGVhbiRUZWFtLlJlYm91bmRzKSwgInBhbGVncmVlbjMiLCAicmVkMyIpLCBsaW5ld2lkdGggPSAwLjIpDQoNCiNMb29raW5nIGF0IGdhbWVzIHRoYXQgaGFkIHRlYW0gdG90YWwgc3RlYWxzIGFib3ZlIG9yIGJlbG93IG1lZGlhbiB0ZWFtIHNlYXNvbiB2YWx1ZQ0KZ2dwbG90KGRhdGEgPSBjdXJyZW50X3NlYXNvbiwgYWVzKERhdGUsIFRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHN0YXRzX2NsZWFuJERhdGUsIGNvbG9yID0gaWZlbHNlKHN0YXRzX2NsZWFuJFRlYW0uU3RlYWxzID4gbWVkaWFuKHN0YXRzX2NsZWFuJFRlYW0uU3RlYWxzKSwgInBhbGVncmVlbjMiLCAicmVkMyIpLCBsaW5ld2lkdGggPSAwLjIpDQoNCiAgZ2dwbG90KGRhdGEgPSBjdXJyZW50X3NlYXNvbiwgYWVzKHg9RGF0ZSwgeT1DaGFuZ2UuVGVhbS5BdmVyYWdlLlJTSS4ubS5wZXIucy4pKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHN0YXRzX2NsZWFuJERhdGUsIGNvbG9yID0gaWZlbHNlKHN0YXRzX2NsZWFuJFRlYW0uU3RlYWxzID4gbWVkaWFuKHN0YXRzX2NsZWFuJFRlYW0uU3RlYWxzKSwgInBhbGVncmVlbjMiLCAicmVkMyIpLCBsaW5ld2lkdGggPSAwLjIpDQoNCiNMb29raW5nIGF0IGdhbWVzIHRoYXQgaGFkIHRlYW0gdG90YWwgYXNzaXN0cyBhYm92ZSBvciBiZWxvdyBtZWRpYW4gdGVhbSBzZWFzb24gdmFsdWUNCmdncGxvdChkYXRhID0gY3VycmVudF9zZWFzb24sIGFlcyhEYXRlLCBUZWFtLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLikpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBzdGF0c19jbGVhbiREYXRlLCBjb2xvciA9IGlmZWxzZShzdGF0c19jbGVhbiRUZWFtLkFzc2lzdHMgPiBtZWRpYW4oc3RhdHNfY2xlYW4kVGVhbS5Bc3Npc3RzKSwgInBhbGVncmVlbjMiLCAicmVkMyIpLCBsaW5ld2lkdGggPSAwLjIpDQoNCmdncGxvdChkYXRhID0gY3VycmVudF9zZWFzb24sIGFlcyh4PURhdGUsIHk9Q2hhbmdlLlRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSAgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBzdGF0c19jbGVhbiREYXRlLCBjb2xvciA9IGlmZWxzZShzdGF0c19jbGVhbiRUZWFtLkFzc2lzdHMgPiBtZWRpYW4oc3RhdHNfY2xlYW4kVGVhbS5Bc3Npc3RzKSwgInBhbGVncmVlbjMiLCAicmVkMyIpLCBsaW5ld2lkdGggPSAwLjIpDQpgYGANCg0KYGBge3IgUGxvdHRpbmcgZ2FtZXMgdGhhdCBhcmUgY29uc2lkZXJlZCBvdmVyYWxsIGdvb2Qgb3IgYmFkIHRocm91Z2hvdXQgc2Vhc29ufQ0KZ2dwbG90KGRhdGEgPSBjdXJyZW50X3NlYXNvbiwgYWVzKERhdGUsIFRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHN0YXRzX2NsZWFuJERhdGVbc3RhdHNfY2xlYW4kVGVhbS5Hb29kLkdhbWUgPT0xIHwgc3RhdHNfY2xlYW4kVGVhbS5CYWQuR2FtZSA9PTFdLCBjb2xvciA9IGlmZWxzZShzdGF0c19jbGVhblsoc3RhdHNfY2xlYW4kVGVhbS5Hb29kLkdhbWUgPT0xIHwgc3RhdHNfY2xlYW4kVGVhbS5CYWQuR2FtZSA9PTEpLF0kVGVhbS5Hb29kLkdhbWUgPT0gMSwgInBhbGVncmVlbjMiLCJyZWQzIikpDQpgYGANCg0KIyMjIyMgQXBwbHlpbmcgcmVndWxhcml6YXRpb24gdGVjaG5pcXVlcyB0byB0ZWFtIGRhdGENCg0KYGBge3J9DQpEYXRlcyA8LSB1bmlxdWUoY3VycmVudF9zZWFzb24kRGF0ZSkNCiNzbW9vdGggPC0gZXhwb25lbnRpYWxfc21vb3RoaW5nKHVuaXF1ZShjdXJyZW50X3NlYXNvbiRUZWFtLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLiksMiwwKQ0KbWEgPC0gbW92aW5nX2F2ZXJhZ2UodW5pcXVlKGN1cnJlbnRfc2Vhc29uJFRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSwgMSkNCiN4NTMgPC0gZml2ZV90aHJlZV94KHVuaXF1ZShjdXJyZW50X3NlYXNvbiRUZWFtLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLikpDQoNCiNjdXJyZW50X3NlYXNvbiRUZWFtLkF2ZXJhZ2UuUlNJLlNtb290aCA8LSByZXAoTkEsNTgwKQ0KY3VycmVudF9zZWFzb24kVGVhbS5BdmVyYWdlLlJTSS5Nb3ZpbmcuQXZlcmFnZSA8LSByZXAoTkEsIDU4MCkNCiNjdXJyZW50X3NlYXNvbiRUZWFtLkF2ZXJhZ2UuUlNJLjUzWCA8LSByZXAoTkEsIDU4MCkNCg0KZm9yKGkgaW4gMToyNSl7DQogICNjdXJyZW50X3NlYXNvbltjdXJyZW50X3NlYXNvbiREYXRlID09IERhdGVzW2ldLDIxXTwtIHNtb290aFtpXQ0KICBjdXJyZW50X3NlYXNvbltjdXJyZW50X3NlYXNvbiREYXRlID09IERhdGVzW2ldLDIzXTwtIG1hW2ldDQogICNjdXJyZW50X3NlYXNvbltjdXJyZW50X3NlYXNvbiREYXRlID09IERhdGVzW2ldLDIzXTwtIHg1M1tpXQ0KfQ0KDQpnZ3Bsb3QoZGF0YT1jdXJyZW50X3NlYXNvbiwgYWVzKERhdGUsIFRlYW0uQXZlcmFnZS5SU0kuTW92aW5nLkF2ZXJhZ2UpKSArDQogIGdlb21fbGluZSgpICsNCmdlb21fdmxpbmUoeGludGVyY2VwdCA9IHN0YXRzX2NsZWFuJERhdGVbc3RhdHNfY2xlYW4kVGVhbS5Hb29kLkdhbWUgPT0xIHwgc3RhdHNfY2xlYW4kVGVhbS5CYWQuR2FtZSA9PTFdLCBjb2xvciA9IGlmZWxzZShzdGF0c19jbGVhblsoc3RhdHNfY2xlYW4kVGVhbS5Hb29kLkdhbWUgPT0xIHwgc3RhdHNfY2xlYW4kVGVhbS5CYWQuR2FtZSA9PTEpLF0kVGVhbS5Hb29kLkdhbWUgPT0gMSwgInBhbGVncmVlbjMiLCJyZWQzIikpDQpgYGANCg0KDQojIyMjIyBBc3Nlc3NpbmcgZWZmZWN0aXZlbmVzcyBvZiBSU0kgYXMgcHJlZGljdG9yIG9mIGluIGdhbWUgc3VjY2Vzcw0KDQpgYGB7ciBHcm91cGluZyBkYXlzIHRvZ2V0aGVyIGJhc2VkIG9uIHdoaWNoIGdhbWVzIHRoZXkgd2VyZSBsZWFkaW5nIHVwIHRvfQ0KI2dldHRpbmcgZGF0ZXMgdGhhdCBoYWQgZ2FtZXMgb24gdGhlbQ0KR2FtZS5EYXlzIDwtIHVuaXF1ZShzdGF0c19jbGVhbiREYXRlKQ0KDQojbnVtYmVyaW5nIHdoaWNoIGdhbWUgaW4gdGhlIHNlYXNvbiBpdCB3YXMNCkdhbWUuTnVtYmVyIDwtIHNlcSgzMCwgMSwgLTEpDQoNCiNtYWtpbmcgZW1wdHkgY29sdW1ucyB0byBiZSBmaWxsZWQgd2l0aCBnYW1lIG51bWJlcg0Kc3RhdHNfY2xlYW4kR2FtZS5OdW1iZXIgPC0gcmVwKE5BLCAzMTUpDQpjdXJyZW50X3NlYXNvbiRHYW1lLk51bWJlciA8LSByZXAoTkEsIDU4MCkNCg0KI2dvaW5nIHRocm91Z2ggZ2FtZXMgZGF0YSBzZXQgYW5kIGxhYmVsaW5nIHdoaWNoIGdhbWUgd2FzIHdoaWNoIHRocm91Z2hvdXQgdGhlIHNlYXNvbg0KIyMgZmlyc3QsIHNlY29uZCwgdGhpcmQsIC4uLiAzMHRoDQpmb3IoaSBpbiAxOjMwKXsNCiAgc3RhdHNfY2xlYW5bc3RhdHNfY2xlYW4kRGF0ZSA9PSBHYW1lLkRheXNbaV0sXSRHYW1lLk51bWJlciA8LSBHYW1lLk51bWJlcltpXQ0KfQ0KDQojZ29pbmcgdGhyb3VnaCBwcmFjdGljZXMgZGF0YSBzZXQgYW5kIGxhYmVsaW5nIHRoZSBjbG9zZXN0IGdhbWUgdGhhdCB0aGUgcHJhY3RpY2Ugd2FzIGJlZm9yZQ0KIyMgd2lsbCBiZSB1c2VkIGZvciBncm91cGluZyBnYW1lcyB0b2dldGhlciBsYXRlcg0KZm9yKGkgaW4gMTozMCl7DQogIGN1cnJlbnRfc2Vhc29uW2N1cnJlbnRfc2Vhc29uJERhdGUgPCBHYW1lLkRheXNbaV0sXSRHYW1lLk51bWJlciA9IDMxLWkNCn0NCmBgYA0KDQoNCg0KYGBge3IgbWFraW5nIHRyYWluaW5nIGFuZCB0ZXN0aW5nIHNldHN9DQojbWFraW5nIG9uZSBkYXRhIHNldCB3aXRoIGV2ZXJ5dGhpbmcgdG9nZXRoZXIgdG8gYXNzZXNzIGVmZmVjdGl2ZW5lc3Mgb2YgUlNJIGFzIGEgcHJlZGljdG9yDQojIyBncm91cGluZyBieSB0aGUgZ2FtZSBwbGF5ZWQgb3IgbGVkIHVwIHRvIGFuZCB0aGUgcGxheWVyIGlkDQpRMV9kYXRhIDwtIGxlZnRfam9pbih4PWN1cnJlbnRfc2Vhc29uLCB5PXN0YXRzX2NsZWFuLCBieT1jKCJhbm9uX2lkIiwgIkdhbWUuTnVtYmVyIikpDQpRMV9kYXRhIDwtIFExX2RhdGEgJT4lDQogIGZpbHRlcihUZWFtLkdvb2QuR2FtZSAlaW4lIGMoMCwxKSkNClExX2RhdGEgPC0gUTFfZGF0YVsxMzo1NDAsXQ0KUTFfZGF0YSA8LSBRMV9kYXRhWy1jKDQ2OCw0NjksNTE0LDUxNSw1MTYpLF0NCg0KI3NldCBzZWVkIHRvIG1ha2UgcmVwcm9kdWNpYmxlLCBzcGxpdHRpbmcgZGF0YSBpbnRvIHRyYWluaW5nIGFuZCB0ZXN0aW5nIHNldHMgKDc1LTI1IHNwbGl0KQ0Kc2V0LnNlZWQoMTIzKQ0Kcm93cyA8LSBzYW1wbGUoMTpucm93KFExX2RhdGEpLCBucm93KFExX2RhdGEpKjAuNzUsIHJlcGxhY2U9RkFMU0UpDQpRMV90cmFpbiA8LSBRMV9kYXRhW3Jvd3MsXQ0KUTFfdGVzdCA8LSBRMV9kYXRhWy1yb3dzLF0NCmBgYA0KDQoNCg0KYGBge3IgbWFraW5nIG1vZGVsIHRvIHByZWRpY3Qgd2hldGhlciBpdCB3YXMgYSBnb29kIHRlYW0gZ2FtZSBvciBub3R9DQojbW9kZWwgdG8gcHJlZGljdCB3aGV0aGVyIGdhbWUgd2FzIGEgZ29vZCBnYW1lIG9yIG5vdCBiYXNlZCBvbiB0ZWFtIGF2ZXJhZ2UgUlNJIGluY3JlYXNlIGxlYWRpbmcgdXAgdG8gdGhhdCBnYW1lDQpRMV9tb2RlbF9nb29kX2dhbWUgPC0gZ2xtKFRlYW0uR29vZC5HYW1lfkNoYW5nZS5UZWFtLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLiwgZGF0YT1RMV90cmFpbiwgZmFtaWx5PSJiaW5vbWlhbCIpDQpzdW1tYXJ5KFExX21vZGVsX2dvb2RfZ2FtZSkNCg0KI3VzaW5nIHRoZSBtb2RlbCBhYm92ZSB0byBtYWtlIHByZWRpY3Rpb24gb24gd2hldGhlciBpdCB3YXMgYSBnb29kIGdhbWUgb3Igbm90IGFuZCBjYWxjdWxhdGluZyBDRVIgKHVzaW5nIDAuNSBhcyB0aHJlc2hvbGQsIG1heSBhZGp1c3QgbGF0ZXIpDQojIyMgQ2hhbmdlZCB0aHJlc2hvbGQgdG8gMC40MyBiYXNlZCBvZmYgb2YgUk9DIGN1cnZlIGRvbmUgYmVsb3cNClExX3Rlc3QkVGVhbS5Hb29kLlByZWQgPC0gaWZlbHNlKHByZWRpY3QuZ2xtKFExX21vZGVsX2dvb2RfZ2FtZSwgUTFfdGVzdCwgdHlwZT0icmVzcG9uc2UiKSA+MC40NiwxLDApDQoNClExX3Rlc3QgJT4lDQogIHN1bW1hcml6ZShDRVIgPSBtZWFuKG5hLm9taXQoVGVhbS5Hb29kLlByZWQgIT0gVGVhbS5Hb29kLkdhbWUpKSkNCmBgYA0KDQpgYGB7ciBtYWtpbmcgYSBtb2RlbCB0byBwcmVkaWN0IHdoZXRoZXIgaXQgd2FzIGEgYmFkIHRlYW0gZ2FtZSBvciBub3R9DQojYnVpbGRpbmcgYmlub21pYWwgbW9kZWwgdG8gcHJlZGljdCB3aGV0aGVyIGl0IHdhcyBhIGJhZCB0ZWFtIGdhbWUgb3Igbm90DQpRMV9tb2RlbF9iYWRfZ2FtZSA8LSBnbG0oVGVhbS5CYWQuR2FtZX5DaGFuZ2UuVGVhbS5BdmVyYWdlLlJTSS4ubS5wZXIucy4sIGRhdGEgPSBRMV90cmFpbiwgZmFtaWx5ID0gImJpbm9taWFsIikNCnN1bW1hcnkoUTFfbW9kZWxfYmFkX2dhbWUpDQoNCiNtYWtpbmcgcHJlZGljdGlvbiBiYXNlZCBvbiB0aGUgbW9kZWwgYW5kIGNhbGN1bGF0aW5nIHRoZSBDRVIgZm9yIHRoZSBtb2RlbCBvbiB0ZXN0IGRhdGENClExX3Rlc3QkVGVhbS5CYWQuUHJlZCA8LSBpZmVsc2UocHJlZGljdC5nbG0oUTFfbW9kZWxfYmFkX2dhbWUsIFExX3Rlc3QsIHR5cGU9InJlc3BvbnNlIikgPjAuMDUsMSwwKQ0KDQpRMV90ZXN0ICU+JQ0KICBzdW1tYXJpemUoQ0VSID0gbWVhbihuYS5vbWl0KFRlYW0uQmFkLlByZWQgIT0gVGVhbS5CYWQuR2FtZSkpKQ0KDQpgYGANCg0KDQojIyMjIyBDcm9zcyBWYWxpZGF0aW5nIHRoZSBUZWFtIE1vZGVscyBhbmQgQ2FsY3VsYXRpbmcgU2Vuc2l0aXZpdHkgYW5kIFNwZWNpZmljaXR5IFJhdGVzIHcvIFJPQw0KDQpgYGB7ciBDcm9zcyB2YWxpZGF0aW5nIHRoZSBnb29kIGdhbWVzIG1vZGVsfQ0Kc2V0LnNlZWQoMTIzKQ0KI21vZGVsIHRvIGJlIHVzZWQgZm9yIGNyb3NzIHZhbGlkYXRpb24gYW5kIFJPQyBjdXJ2ZQ0KbW9kZWxfZ29vZF90ZWFtX2N2IDwtIGdsbShUZWFtLkdvb2QuR2FtZSB+IENoYW5nZS5UZWFtLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLiwgZGF0YT1RMV9kYXRhLCBmYW1pbHk9ImJpbm9taWFsIikNCg0KI01ha2luZyBwcmVkaWN0aW9ucyBmb3IgUk9DIGN1cnZlDQojJFRlYW0uR29vZC5HYW1lLlByZWQgPC0gcHJlZGljdChtb2RlbF9nb29kX3RlYW1fY3YsIHR5cGU9InJlc3BvbnNlIikNCg0KI21ha2luZyBST0MgY3VydmUNCiNwcmVkIDwtIHByZWRpY3Rpb24ocHJlZGljdGlvbnMgPSBRMV9kYXRhJFRlYW0uR29vZC5HYW1lLlByZWQsDQojICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IFExX2RhdGEkVGVhbS5Hb29kLkdhbWUpDQojcGVyZiA8LSBwZXJmb3JtYW5jZShwcmVkLG1lYXN1cmU9J3RucicseC5tZWFzdXJlPSd0cHInKQ0KI3Bsb3QocGVyZiwgY29sb3JpemU9VFJVRSkNCg0KDQojY29zdCBmdW5jdGlvbiBmb3IgQ0VSIGluIGNyb3NzIHZhbGlkYXRpb24NCmNvc3QgPC0gZnVuY3Rpb24ob2JzLCBwcmVkKXsNCiAgbWVhbigocHJlZCA8PSAwLjQ2KSAmIG9icz09MSB8IChwcmVkID4gMC40NikgJiBvYnM9PTApDQp9DQoNCiNjcm9zcyB2YWxpZGF0aW5nIG1vZGVsDQpnb29kX3RlYW1fY3YgPC0gY3YuZ2xtKGRhdGE9UTFfZGF0YSxnbG1maXQ9bW9kZWxfZ29vZF90ZWFtX2N2LGNvc3QsSz01KQ0KDQojZXh0cmFjdCBhdmVyYWdlIGVycm9yDQpnb29kX3RlYW1fY3YkZGVsdGFbMV0NCg0KUTFfZGF0YSRUZWFtLkdvb2QuR2FtZS5QcmVkIDwtIGlmZWxzZShwcmVkaWN0KG1vZGVsX2dvb2RfdGVhbV9jdiwgdHlwZT0icmVzcG9uc2UiKT4wLjQ2LDEsMCkNCg0KI2xvb2tpbmcgYXQgc2Vuc2l0aXZpdHkgYW5kIHNwZWNpZmljaXR5DQp0YWJsZSh4PVExX2RhdGEkVGVhbS5Hb29kLkdhbWUuUHJlZCwgeT1RMV9kYXRhJFRlYW0uR29vZC5HYW1lKQ0KYGBgDQoNCg0KYGBge3IgQ3Jvc3MgdmFsaWRhdGluZyB0aGUgYmFkIGdhbWVzIG1vZGVsfQ0Kc2V0LnNlZWQoMTIzKQ0KI21vZGVsIHRvIGJlIHVzZWQgZm9yIGNyb3NzIHZhbGlkYXRpb24gYW5kIFJPQyBjdXJ2ZQ0KbW9kZWxfYmFkX3RlYW1fY3YgPC0gZ2xtKFRlYW0uQmFkLkdhbWUgfiBDaGFuZ2UuVGVhbS5BdmVyYWdlLlJTSS4ubS5wZXIucy4sIGRhdGE9UTFfZGF0YSwgZmFtaWx5PSJiaW5vbWlhbCIpDQoNCiNNYWtpbmcgcHJlZGljdGlvbnMgZm9yIFJPQyBjdXJ2ZQ0KI1ExX2RhdGEkVGVhbS5CYWQuR2FtZS5QcmVkIDwtIHByZWRpY3QobW9kZWxfYmFkX3RlYW1fY3YsIHR5cGU9InJlc3BvbnNlIikNCg0KI21ha2luZyBST0MgY3VydmUNCiNwcmVkIDwtIHByZWRpY3Rpb24ocHJlZGljdGlvbnMgPSBRMV9kYXRhJFRlYW0uQmFkLkdhbWUuUHJlZCwNCiMgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gUTFfZGF0YSRUZWFtLkJhZC5HYW1lKQ0KI3BlcmYgPC0gcGVyZm9ybWFuY2UocHJlZCxtZWFzdXJlPSdmbnInLHgubWVhc3VyZT0nZnByJykNCiNwbG90KHBlcmYsIGNvbG9yaXplPVRSVUUpDQoNCg0KI2Nvc3QgZnVuY3Rpb24gZm9yIENFUiBpbiBjcm9zcyB2YWxpZGF0aW9uDQpjb3N0IDwtIGZ1bmN0aW9uKG9icywgcHJlZCl7DQogIG1lYW4oKHByZWQgPD0gMC4wNSkgJiBvYnM9PTEgfCAocHJlZCA+IDAuMDUpICYgb2JzPT0wKQ0KfQ0KDQojY3Jvc3MgdmFsaWRhdGluZyBtb2RlbA0KYmFkX3RlYW1fY3YgPC0gY3YuZ2xtKGRhdGE9UTFfZGF0YSxnbG1maXQ9bW9kZWxfYmFkX3RlYW1fY3YsY29zdCxLPTUpDQoNCiNleHRyYWN0IGF2ZXJhZ2UgZXJyb3INCmJhZF90ZWFtX2N2JGRlbHRhWzFdDQoNClExX2RhdGEkVGVhbS5CYWQuR2FtZS5QcmVkIDwtIGlmZWxzZShwcmVkaWN0KG1vZGVsX2JhZF90ZWFtX2N2LCB0eXBlPSJyZXNwb25zZSIpPjAuMDUsMSwwKQ0KDQojbG9va2luZyBhdCBzZW5zaXRpdml0eSBhbmQgc3BlY2lmaWNpdHkNCnRhYmxlKHg9UTFfZGF0YSRUZWFtLkJhZC5HYW1lLlByZWQsIHk9UTFfZGF0YSRUZWFtLkJhZC5HYW1lKQ0KYGBgDQpJbiBvcmRlciB0byBsaW1pdCB2YXJpYWJpbGl0eSBhbmQgbWltaWMgcGFzdCByZXNlYXJjaCwgYmluYXJ5IHZhcmlhYmxlcyB3ZXJlIGNyZWF0ZWQuIE90aGVyIHJlc2VhcmNoIHVzZWQgdG9wIHJ1bm5pbmcgc3BlZWQgaW4gZ2FtZXMgdG8gbWVhc3VyZSBleHBsb3NpdmVuZXNzIG9mIGFuIGF0aGxldGUgYXQgYSBwYXJ0aWN1bGFyIHRpbWUgYW5kIHdlcmUgY29tcGFyZWQgdG8gbWVkaWFuIHRvcCBpbiBnYW1lIHJ1bm5pbmcgc3BlZWQgdGhyb3VnaG91dCB0aGUgc2Vhc29uIHRvIGRlZmluZSBzdWNjZXNzLiBUaGUgZGF0YSBzZXRzIGdpdmVuIGRpZCBub3QgaGF2ZSBpbiBnYW1lIHJ1bm5pbmcgc3BlZWQgc28gYSBjb21iaW5hdGlvbiBvZiBzdGVhbHMsIGFzc2lzdHMsIGFuZCByZWJvdW5kcyB3ZXJlIHVzZWQgYXMgYSBwcm94eSBmb3IgYSBtZWFzdXJlIG9mIGV4cGxvc2l2ZW5lc3MuIEEgYmluYXJ5IHZhcmlhYmxlIHdhcyBjcmVhdGVkIHRoYXQgbWVhc3VyZWQgaWYgdGhlIHRlYW0gcGVyZm9ybWVkIGFib3ZlIG9yIGJlbG93IG1lZGlhbiBpbiBhbGwgdGhyZWUgbWV0cmljcyAoMSkgb3IgaWYgb25lIG9yIG1vcmUgb2YgdGhlIGxpc3RlZCBtZXRyaWNzIHdlcmUgYmVsb3cgdGhlIHNlYXNvbiB0ZWFtIG1lZGlhbiAoMCkuIFRoaXMgaXMgd2hhdCB3aWxsIGJlIHByZWRpY3RlZCB0aHJvdWdoIGNoYW5nZXMgaW4gUlNJIG9mIHRoZSB0ZWFtIHRocm91Z2hvdXQgdGhlIHNlYXNvbi4gU2hvd24gYWJvdmUgYXJlIHRoZSBjcm9zcyB2YWxpZGF0ZWQgcHJlZGljdGVkIGVycm9yIHJhdGVzIGZvciB0aGUgbW9kZWxzIHRoYXQgYXJlIHVzZWQgdG8gcHJlZGljdCB3aGV0aGVyIHRoZSB0ZWFtIHdpbGwgcGxheSBhYm92ZSB0aGVpciBtZWRpYW4gZ2FtZSBwbGF5IG9yIGJlbG93IHRoZWlyIG1lZGlhbiBnYW1lIHBsYXkgaW4gYSBnaXZlbiBnYW1lLiANCg0KRm9yIHRoZSBmaXJzdCBtb2RlbCwgaXQgaXMgdHJ5aW5nIHRvIHByZWRpY3Qgd2hldGhlciBvciBub3QgdGhlIHRlYW0gd2lsbCBoYXZlIHRoZWlyIHN0ZWFscywgcmVib3VuZHMsIGFuZCBhc3Npc3RzLCBhbGwgYWJvdmUgdGhlaXIgc2Vhc29uIG1lZGlhbiBmb3IgYSBnaXZlbiBnYW1lIHdoZXJlIHRoZSBvbmx5IHByZWRpY3RvciBpcyB0aGUgY2hhbmdlIGluIFJTSSBtZWFzdXJlZCB0aGUgcHJldmlvdXMgZGF5LiBUaGlzIG1vZGVsIGhhcyBhIGNyb3NzIHZhbGlkYXRlZCBjbGFzc2lmaWNhdGlvbiBlcnJvciByYXRlIG9mIGFyb3VuZCAwLjQgbWVhbmluZyB0aGF0IGl0IHdpbGwgbWFrZSBhIHdyb25nIHByZWRpY3Rpb24gYXJvdW5kIDQwJSBvZiB0aGUgdGltZS4gT3V0IG9mIHRoZSBtaXNjbGFzc2lmaWNhdGlvbnMsIHRoZSBtb2RlbCB3aWxsIGdlbmVyYWxseSB0ZW5kIHRvIHByZWRpY3QgdGhhdCBhIGdhbWUgd2lsbCBub3QgYmUgYWJvdmUgbWVkaWFuIHdoZW4gaXQgaXMuIEluIGZhY3QsIHRoZSBtb2RlbCB3aWxsIHByZWRpY3QgdGhhdCBhIGdhbWUgd2lsbCBub3QgYmUgYWJvdmUgbWVkaWFuIHdoZW4gaXQgYWN0dWFsbHkgaXMsIGFib3V0IDMgdGltZXMgYXMgb2Z0ZW4gYXMgaXQgd2lsbCBjb3JyZWN0bHkgcHJlZGljdCBhbiBhYm92ZSBtZWRpYW4gZ2FtZSB3aWxsIGJlIGFib3ZlIG1lZGlhbi4gRHVlIHRvIHRoaXMgbWFqb3IgbGFjayBvZiBzZW5zaXRpdml0eSwgaXQncyBzb21ld2hhdCBzYWZlIHRvIHNheSB0aGF0IGNoYW5nZXMgaW4gUlNJIG1heSBub3QgYmUgYSBnb29kIHByZWRpY3RvciBmb3IgaW4gZ2FtZSBzdWNjZXNzIGJhc2VkIG9uIHRoZSBjb25zdHJhaW50cyBtYWRlIGluIHRoaXMgYW5hbHlzaXMuIA0KDQpUaGUgc2Vjb25kIG1vZGVsIGlzIHRyeWluZyB0byBwcmVkaWN0IHdoZXRoZXIgb3Igbm90IHRoZSB0ZWFtIHdpbGwgaGF2ZSB0aGUgdG90YWwgcmVib3VuZHMsIGFzc2lzdHMsIGFuZCBzdGVhbHMgZm9yIHRoZSBnYW1lIGFsbCBiZWxvdyBtZWRpYW4gb3Igbm90LiBXaXRoIHRoaXMgbW9kZWwsIHRoZSBjcm9zcyB2YWxpZGF0ZWQgY2xhc3NpZmljYXRpb24gZXJyb3IgcmF0ZSBpcyBhcm91bmQgMC4yLiBUaGlzIHN1Z2dlc3RzIHRoYXQgdGhlIG1vZGVsIHdpbGwgbWFrZSBhbiBpbmNvcnJlY3QgY2xhc3NpZmljYXRpb24gYXJvdW5kIDIwJSBvZiB0aGUgdGltZS4gT3V0IG9mIHRoZSBpbmNvcnJlY3QgY2xhc3NpZmljYXRpb25zIGFsbCBvZiB0aGVtIHdlcmUgdGltZXMgaW4gd2hpY2ggaW4gdGhlIG1vZGVsIHByZWRpY3RlZCBmb3IgdGhlIHRlYW0gdG8gcGVyZm9ybSBiZWxvdyB0aGVpciBtZWRpYW4gaW4gZXhwbG9zaXZlbmVzcyBtZXRyaWNzIGluIHRoZSBnYW1lIGJ1dCB0aGUgdGVhbSBwZXJmb3JtZWQgYWJvdmUgdGhlaXIgbWVkaWFuIGluIGF0IGxlYXN0IG9uZSBtZXRyaWMuIFRoaXMgc3VnZ2VzdHMgdGhhdCB0aGlzIG1vZGVsIGlzIG1ha2luZyBwcmVkaWN0aW9ucyB0aGF0IHRoZSB0ZWFtIHdpbGwgcGVyZm9ybSAicG9vcmx5IiBvciBiZWxvdyBtZWRpYW4gbW9yZSBmcmVxdWVudGx5IHRoYW4gd2hhdCBpcyBhY3R1YWxseSBoYXBwZW5pbmcuIEluIGZhY3QsIHdoZW4gdGhlIG1vZGVsIHByZWRpY3RzIHRoYXQgdGhlIHRlYW0gd2lsbCBwZXJmb3JtIGJlbG93IHRoZWlyIHNlYXNvbiBtZWRpYW4gZ2FtZSBwbGF5LCB0aGUgcHJlZGljdGlvbnMgd2lsbCBiZSBpbmNvcnJlY3QgbW9yZSBvZnRlbiB0aGFuIGNvcnJlY3QuIEl0J3MgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCB0aGlzIG1vZGVsIGNvcnJlY3RseSBpZGVudGlmaWVkIGFsbCBvZiB0aGUgZ2FtZXMgaW4gd2hpY2ggdGhlIHRlYW0gcGVyZm9ybWVkIGJlbG93IG1lZGlhbi4gVGhpcyBzdWdnZXN0cyB0aGF0IHRoZXJlIGlzIHByZWRpY3RpdmUgcG93ZXIgaW4gY2hhbmdlcyBpbiBSU0kgZm9yIGluIGdhbWUgcGVyZm9ybWFuY2UgdGhhdCBpcyBtZWFzdXJlZCB0byBiZSBiZWxvdyBtZWRpYW4gZm9yIHRoZSB0ZWFtLiANCg0KRm9yIHRoZSBkYXRhIHBvaW50cyB0aGF0IHdlcmUgbWlzY2xhc3NpZmllZCBieSB0aGUgbW9kZWwsIGl0IG1heSBiZSB1c2VmdWwgdG8gbG9vayBhdCB0aGUgbWV0cmljcyBmb3IgdGhvc2UgZ2FtZXMgYW5kIGlkZW50aWZ5IGhvdyB0aGUgdGVhbSBwZXJmb3JtZWQuIFNpbmNlIHRoaXMgYW5hbHlzaXMgZGVmaW5lZCBhIGJhZCBnYW1lIGFzIGEgZ2FtZSBpbiB3aGljaCB0aGUgdGVhbSBwZXJmb3JtZWQgYmVsb3cgbWVkaWFuIGluIHN0ZWFscywgYXNzaXN0cywgYW5kIHJlYm91bmRzIG9yIG5vdCwgaXQgbWF5IGJlIHVzZWZ1bCB0byBzZWUgd2hpY2ggbWV0cmljcyB0aGV5IHBlcmZvcm1lZCBiZWxvdyBtZWRpYW4gaW4gZ2FtZXMgdGhhdCB3ZXJlIHByZWRpY3RlZCB0byBiZSAiYmFkIGdhbWVzIiBidXQgd2hlcmUgbm90IGJlbG93IG1lZGlhbiBpbiBhbGwgdGhyZWUgbWV0cmljcy4gVGhlIG1vZGVsIGNvdWxkIGhhdmUgcG90ZW50aWFsbHkgaWRlbnRpZmllZCBnYW1lcyB0aGF0IHdlcmUgcG9vciBidXQgd2VyZSBub3QgcG9vciBlbm91Z2ggcGVyIHNheSB0byBiZSBjbGFzc2lmaWVkIGFzIGEgImJhZCBnYW1lIiBpbiB0aGlzIGFuYWx5c2lzLiANCg0KIyMgUXVlc3Rpb24gMg0KDQojIyMgQXJlIGNoYW5nZXMgaW4gUlNJIHJlbGF0ZWQgdG8gaW5kaXZpZHVhbCBzdGF0aXN0aWNhbCBnYW1lIHBlcmZvcm1hbmNlPw0KDQpgYGB7ciBMb29raW5nIGF0ICJJRF80MiIgZm9yIHRoaXMgZmlyc3QgYW5hbHlzaXN9DQojTG9va2luZyBhdCBnYW1lcyB0aGF0IGhhZCBhYm92ZSBvciBiZWxvdyBtZWRpYW4gcmVib3VuZHMgdGhyb3VnaG91dCB0aGUgc2Vhc29uDQpnZ3Bsb3QoZGF0YSA9IGN1cnJlbnRfc2Vhc29uW2N1cnJlbnRfc2Vhc29uJGFub25faWQgPT0gIklEXzQyIixdLCBhZXMoRGF0ZSwgUGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLikpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBzdGF0c19jbGVhbiREYXRlW3N0YXRzX2NsZWFuJGFub25faWQgPT0gIklEXzQyIl0sIGNvbG9yID0gaWZlbHNlKHN0YXRzX2NsZWFuW3N0YXRzX2NsZWFuJGFub25faWQgPT0gIklEXzQyIixdJFJlYm91bmRzID49IG1lZGlhbihzdGF0c19jbGVhbltzdGF0c19jbGVhbiRhbm9uX2lkID09ICJJRF80MiIsXSRSZWJvdW5kcyksICJwYWxlZ3JlZW4zIiwgInJlZDMiKSkNCg0KI0xvb2tpbmcgYXQgZ2FtZXMgdGhhdCBoYWQgYWJvdmUgb3IgYmVsb3cgbWVkaWFuIHN0ZWFscyB0aHJvdWdob3V0IHRoZSBzZWFzb24NCmdncGxvdChkYXRhID0gY3VycmVudF9zZWFzb25bY3VycmVudF9zZWFzb24kYW5vbl9pZCA9PSAiSURfNDIiLF0sIGFlcyhEYXRlLCBQbGF5ZXIuQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHN0YXRzX2NsZWFuJERhdGVbc3RhdHNfY2xlYW4kYW5vbl9pZCA9PSAiSURfNDIiXSwgY29sb3IgPSBpZmVsc2Uoc3RhdHNfY2xlYW5bc3RhdHNfY2xlYW4kYW5vbl9pZCA9PSAiSURfNDIiLF0kU3RlYWxzID49IG1lZGlhbihzdGF0c19jbGVhbltzdGF0c19jbGVhbiRhbm9uX2lkID09ICJJRF80MiIsXSRTdGVhbHMpLCAicGFsZWdyZWVuMyIsICJyZWQzIikpDQoNCiNMb29raW5nIGF0IGdhbWVzIHRoYXQgaGFkIGFib3ZlIG9yIGJlbG93IG1lZGlhbiBhc3Npc3RzIHRocm91Z2hvdXQgdGhlIHNlYXNvbg0KZ2dwbG90KGRhdGEgPSBjdXJyZW50X3NlYXNvbltjdXJyZW50X3NlYXNvbiRhbm9uX2lkID09ICJJRF80MiIsXSwgYWVzKERhdGUsIFBsYXllci5BdmVyYWdlLlJTSS4ubS5wZXIucy4pKSArDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gc3RhdHNfY2xlYW4kRGF0ZVtzdGF0c19jbGVhbiRhbm9uX2lkID09ICJJRF80MiJdLCBjb2xvciA9IGlmZWxzZShzdGF0c19jbGVhbltzdGF0c19jbGVhbiRhbm9uX2lkID09ICJJRF80MiIsXSRBc3Npc3RzID49IG1lZGlhbihzdGF0c19jbGVhbltzdGF0c19jbGVhbiRhbm9uX2lkID09ICJJRF80MiIsXSRBc3Npc3RzKSwgInBhbGVncmVlbjMiLCAicmVkMyIpKQ0KYGBgDQoNCmBgYHtyIExvb2tpbmcgYXQgb3ZlcmFsbCBnb29kIG9yIGJhZCBnYW1lIGZvciAiSURfNDIifQ0KZ2dwbG90KGRhdGEgPSBjdXJyZW50X3NlYXNvbltjdXJyZW50X3NlYXNvbiRhbm9uX2lkID09ICJJRF80MiIsXSwgYWVzKERhdGUsIFBsYXllci5BdmVyYWdlLlJTSS4ubS5wZXIucy4pKSArDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gc3RhdHNfY2xlYW4kRGF0ZVtzdGF0c19jbGVhbiRhbm9uX2lkID09ICJJRF80MiIgJiAoc3RhdHNfY2xlYW4kUGxheWVyLkdvb2QuR2FtZSA9PSAxIHwgc3RhdHNfY2xlYW4kUGxheWVyLkJhZC5HYW1lID09MSldLCBjb2xvciA9IGlmZWxzZShzdGF0c19jbGVhbltzdGF0c19jbGVhbiRhbm9uX2lkID09ICJJRF80MiIgJiAoc3RhdHNfY2xlYW4kUGxheWVyLkdvb2QuR2FtZSA9PSAxIHwgc3RhdHNfY2xlYW4kUGxheWVyLkJhZC5HYW1lID09MSksXSRQbGF5ZXIuR29vZC5HYW1lID09IDEsICJwYWxlZ3JlZW4zIiwicmVkMyIpKQ0KDQpnZ3Bsb3QoZGF0YSA9IGN1cnJlbnRfc2Vhc29uW2N1cnJlbnRfc2Vhc29uJGFub25faWQgPT0gIklEXzQyIixdLCBhZXMoRGF0ZSwgQ2hhbmdlLlBsYXllci5BdmVyYWdlLlJTSS4ubS5wZXIucy4pKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdD0wKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHN0YXRzX2NsZWFuJERhdGVbc3RhdHNfY2xlYW4kYW5vbl9pZCA9PSAiSURfNDIiICYgKHN0YXRzX2NsZWFuJFBsYXllci5Hb29kLkdhbWUgPT0gMSB8IHN0YXRzX2NsZWFuJFBsYXllci5CYWQuR2FtZSA9PTEpXSwgY29sb3IgPSBpZmVsc2Uoc3RhdHNfY2xlYW5bc3RhdHNfY2xlYW4kYW5vbl9pZCA9PSAiSURfNDIiICYgKHN0YXRzX2NsZWFuJFBsYXllci5Hb29kLkdhbWUgPT0gMSB8IHN0YXRzX2NsZWFuJFBsYXllci5CYWQuR2FtZSA9PTEpLF0kUGxheWVyLkdvb2QuR2FtZSA9PSAxLCAicGFsZWdyZWVuMyIsInJlZDMiKSkNCmBgYA0KDQoNCg0KIyMjIyMjIEFwcGx5aW5nIHJlZ3VsYXJpemF0aW9uIHRlY2huaXF1ZXMgdG8gcGxheWVyIGRhdGENCg0KYGBge3J9DQpzbW9vdGggPC0gZXhwb25lbnRpYWxfc21vb3RoaW5nKHVuaXF1ZShjdXJyZW50X3NlYXNvbiRUZWFtLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLiksMiwwKQ0KbWEgPC0gbW92aW5nX2F2ZXJhZ2UodW5pcXVlKGN1cnJlbnRfc2Vhc29uJFRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSwgMSkNCng1MyA8LSBmaXZlX3RocmVlX3godW5pcXVlKGN1cnJlbnRfc2Vhc29uJFRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSkNCg0KY3VycmVudF9zZWFzb24kVGVhbS5BdmVyYWdlLlJTSS5TbW9vdGggPC0gcmVwKE5BLDU4MCkNCmN1cnJlbnRfc2Vhc29uJFRlYW0uQXZlcmFnZS5SU0kuTW92aW5nLkF2ZXJhZ2UgPC0gcmVwKE5BLCA1ODApDQpjdXJyZW50X3NlYXNvbiRUZWFtLkF2ZXJhZ2UuUlNJLjUzWCA8LSByZXAoTkEsIDU4MCkNCg0KZm9yKGkgaW4gMToyNSl7DQogIGN1cnJlbnRfc2Vhc29uW2N1cnJlbnRfc2Vhc29uJERhdGUgPT0gRGF0ZXNbaV0sMjFdPC0gc21vb3RoW2ldDQogIGN1cnJlbnRfc2Vhc29uW2N1cnJlbnRfc2Vhc29uJERhdGUgPT0gRGF0ZXNbaV0sMjJdPC0gbWFbaV0NCiAgY3VycmVudF9zZWFzb25bY3VycmVudF9zZWFzb24kRGF0ZSA9PSBEYXRlc1tpXSwyM108LSB4NTNbaV0NCn0NCg0KZ2dwbG90KGRhdGE9Y3VycmVudF9zZWFzb24sIGFlcyhEYXRlLCBUZWFtLkF2ZXJhZ2UuUlNJLk1vdmluZy5BdmVyYWdlKSkgKw0KICBnZW9tX2xpbmUoKSArDQpnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBzdGF0c19jbGVhbiREYXRlW3N0YXRzX2NsZWFuJFRlYW0uR29vZC5HYW1lID09MSB8IHN0YXRzX2NsZWFuJFRlYW0uQmFkLkdhbWUgPT0xXSwgY29sb3IgPSBpZmVsc2Uoc3RhdHNfY2xlYW5bKHN0YXRzX2NsZWFuJFRlYW0uR29vZC5HYW1lID09MSB8IHN0YXRzX2NsZWFuJFRlYW0uQmFkLkdhbWUgPT0xKSxdJFRlYW0uR29vZC5HYW1lID09IDEsICJwYWxlZ3JlZW4zIiwicmVkMyIpKQ0KYGBgDQoNCiMjIyMjIyBBc3Nlc3NpbmcgZWZmZWN0aXZlbmVzcyBvZiBSU0kgYXMgcHJlZGljdG9yIG9mIGluIGdhbWUgc3VjY2Vzcw0KDQojIyMjIyMjIEdvb2QgR2FtZXMgTW9kZWxzDQpgYGB7ciBNYWtpbmcgY29tcGxldGVseSBwb29sZWQgbW9kZWwgZm9yIGdvb2QgZ2FtZXN9DQojYnVpbGRpbmcgY29tcGxldGVseSBwb29sZWQgbW9kZWwgZm9yIHBsYXllciBSU0kgY2hhbmdlcyBhbmQgZ29vZCBnYW1lcw0KUTJfbW9kZWxfZ29vZF9nYW1lX3Bvb2xlZCA8LSBnbG0oUGxheWVyLkdvb2QuR2FtZX5DaGFuZ2UuUGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLiwgZGF0YT1RMV90cmFpbiwgZmFtaWx5ID0gImJpbm9taWFsIikNCnN1bW1hcnkoUTJfbW9kZWxfZ29vZF9nYW1lX3Bvb2xlZCkNCg0KI21ha2luZyBwcmVkaWN0aW9ucyB3aXRoIHRoZSBwb29sZWQgbW9kZWwgZm9yIGdvb2QgZ2FtZXMNClExX3Rlc3QkUGxheWVyLkdvb2QuUG9vbGVkLlByZWQgPC0gaWZlbHNlKHByZWRpY3QoUTJfbW9kZWxfZ29vZF9nYW1lX3Bvb2xlZCwgUTFfdGVzdCk+MC41LDEsMCkNCg0KI2NhbGN1bGF0aW5nIHRoZSBDRVIgb2YgdGhlIG1vZGVsIG9uIHRoZSB0ZXN0IGRhdGENCiNRMV90ZXN0ICU+JQ0KIyBzdW1tYXJpemUoQ0VSID0gbWVhbihQbGF5ZXIuR29vZC5HYW1lICE9IFBsYXllci5Hb29kLlBvb2xlZC5QcmVkKSkNCmBgYA0KDQpgYGB7ciBtYWtpbmcgdW5wb29sZWQgbW9kZWwgZm9yIGdvb2QgZ2FtZXN9DQojbWFraW5nIHVucG9vbGVkIG1vZGVsIGZvciBwbGF5ZXJzDQpRMl9tb2RlbF9nb29kX2dhbWVfdW5wb29sZWQgPC1nbG1lcihQbGF5ZXIuR29vZC5HYW1lfkNoYW5nZS5QbGF5ZXIuQXZlcmFnZS5SU0kuLm0ucGVyLnMuICsgKENoYW5nZS5QbGF5ZXIuQXZlcmFnZS5SU0kuLm0ucGVyLnMufGFub25faWQpLCBkYXRhPVExX3RyYWluLCBmYW1pbHkgPSAiYmlub21pYWwiKQ0Kc3VtbWFyeShRMl9tb2RlbF9nb29kX2dhbWVfdW5wb29sZWQpDQoNCiNtYWtpbmcgcHJlZGljdGlvbnMgZm9yIHVucG9vbGVkIG1vZGVsIG9uIHRoZSB0ZXN0IGRhdGEgKGNhbGN1bGF0ZWQgd2l0aCBwcm9iYWJpbGl0eSkNClExX3Rlc3QkUGxheWVyLkdvb2QuVW5wb29sZWQuUHJlZCA8LSBpZmVsc2UocHJlZGljdChRMl9tb2RlbF9nb29kX2dhbWVfdW5wb29sZWQsIFExX3Rlc3QsIHR5cGU9InJlc3BvbnNlIik+MC40NiwxLDApDQoNCiNjYWxjdWxhdGluZyBDRVIgb2YgdW5wb29sZWQgbW9kZWwNClExX3Rlc3QgJT4lDQogIHN1bW1hcml6ZShDRVIgPSBtZWFuKFBsYXllci5Hb29kLlVucG9vbGVkLlByZWQgIT0gUGxheWVyLkdvb2QuR2FtZSkpDQpgYGANCg0KDQpgYGB7ciBNYWtpbmcgY29tcGxldGVseSBwb29sZWQgbW9kZWwgZm9yIGJhZCBnYW1lc30NCiNidWlsZGluZyBjb21wbGV0ZWx5IHBvb2xlZCBtb2RlbCBmb3IgcGxheWVyIFJTSSBjaGFuZ2VzIGFuZCBiYWQgZ2FtZXMNClEyX21vZGVsX2JhZF9nYW1lX3Bvb2xlZCA8LSBnbG0oUGxheWVyLkJhZC5HYW1lfkNoYW5nZS5QbGF5ZXIuQXZlcmFnZS5SU0kuLm0ucGVyLnMuLCBkYXRhPVExX3RyYWluLCBmYW1pbHkgPSAiYmlub21pYWwiKQ0Kc3VtbWFyeShRMl9tb2RlbF9iYWRfZ2FtZV9wb29sZWQpDQoNCiNtYWtpbmcgcHJlZGljdGlvbnMgZm9yIGJhZCBnYW1lcyB3aXRoIHBvb2xlZCBtb2RlbCBvbiB0ZXN0IGRhdGENClExX3Rlc3QkUGxheWVyLkJhZC5Qb29sZWQuUHJlZCA8LSBpZmVsc2UocHJlZGljdChRMl9tb2RlbF9iYWRfZ2FtZV9wb29sZWQsIFExX3Rlc3QpPjAuNSwxLDApDQoNCiNjYWxjdWxhdGluZyBDRVIgZm9yIGJhZCBnYW1lcyB3aXRoIHBvb2xlZCBtb2RlbA0KI1ExX3Rlc3QgJT4lDQojICBzdW1tYXJpemUoQ0VSID0gbWVhbihQbGF5ZXIuQmFkLkdhbWUgIT0gUGxheWVyLkJhZC5Qb29sZWQuUHJlZCkpDQpgYGANCg0KDQoNCmBgYHtyIG1ha2luZyB1bnBvb2xlZCBtb2RlbCBmb3IgYmFkIGdhbWVzfQ0KI21ha2luZyB1bnBvb2xlZCBtb2RlbCBmb3IgYmFkIGdhbWVzDQpRMl9tb2RlbF9iYWRfZ2FtZV91bnBvb2xlZCA8LWdsbWVyKFBsYXllci5CYWQuR2FtZX5DaGFuZ2UuUGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLiArIChDaGFuZ2UuUGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLnxhbm9uX2lkKSwgZGF0YT1RMV90cmFpbiwgZmFtaWx5ID0gImJpbm9taWFsIikNCnN1bW1hcnkoUTJfbW9kZWxfYmFkX2dhbWVfdW5wb29sZWQpDQoNClExX3Rlc3QkUGxheWVyLkJhZC5VbnBvb2xlZC5QcmVkIDwtIGlmZWxzZShwcmVkaWN0KFEyX21vZGVsX2JhZF9nYW1lX3VucG9vbGVkLCBRMV90ZXN0LCB0eXBlPSJyZXNwb25zZSIpPjAuMDMsMSwwKQ0KDQpRMV90ZXN0ICU+JQ0KICBzdW1tYXJpemUoQ0VSID0gbWVhbihQbGF5ZXIuQmFkLlVucG9vbGVkLlByZWQgIT0gUGxheWVyLkJhZC5HYW1lKSkNCmBgYA0KDQoNCg0KDQojIyMjIyBDcm9zcyBWYWxpZGF0aW5nIEVycm9ycyBmb3IgR29vZCBhbmQgQmFkIEdhbWVzIHdpdGggUk9DIEN1cnZlcw0KYGBge3IgY3Jvc3MgdmFsaWRhdGluZyBwb29sZWQgbW9kZWwgZm9yIGdvb2QgZ2FtZXN9DQpzZXQuc2VlZCgxMjMpDQoNCiNtb2RlbCB0byBiZSB1c2VkIGZvciBjcm9zcyB2YWxpZGF0aW9uDQptb2RlbF9nb29kX3BsYXllcl9wb29sZWRfY3YgPC0gZ2xtKFBsYXllci5Hb29kLkdhbWUgfiBDaGFuZ2UuUGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLiwgZGF0YT1RMV9kYXRhLCBmYW1pbHk9ImJpbm9taWFsIikNCg0KDQojUTFfZGF0YSRQbGF5ZXIuR29vZC5HYW1lLlBvb2xlZC5QcmVkIDwtIHByZWRpY3QobW9kZWxfZ29vZF9wbGF5ZXJfcG9vbGVkX2N2LCB0eXBlPSJyZXNwb25zZSIpDQoNCiNwcmVkIDwtIHByZWRpY3Rpb24ocHJlZGljdGlvbnMgPSBRMV9kYXRhJFBsYXllci5Hb29kLkdhbWUuUG9vbGVkLlByZWQsDQojICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IFExX2RhdGEkUGxheWVyLkdvb2QuR2FtZSkNCiNwZXJmIDwtIHBlcmZvcm1hbmNlKHByZWQsbWVhc3VyZT0ndG5yJyx4Lm1lYXN1cmU9J3RwcicpDQojcGxvdChwZXJmLCBjb2xvcml6ZT1UUlVFKQ0KI2FibGluZShhPTAsIGI9MSkNCg0KY29zdCA8LSBmdW5jdGlvbihvYnMsIHByZWQpew0KICBtZWFuKChwcmVkIDw9LjQ5KSAmb2JzPT0xIHwgKHByZWQgPiAwLjQ5KSAmIG9icz09MCkNCn0NCg0KI2Nyb3NzIHZhbGlkYXRpbmcgbW9kZWwNCmdvb2RfcGxheWVyX2N2IDwtIGN2LmdsbShkYXRhPVExX2RhdGEsZ2xtZml0PW1vZGVsX2dvb2RfcGxheWVyX3Bvb2xlZF9jdixjb3N0LEs9NSkNCg0KI2V4dHJhY3QgYXZlcmFnZSBlcnJvcg0KZ29vZF9wbGF5ZXJfY3YkZGVsdGFbMV0NCg0KUTFfZGF0YSRQbGF5ZXIuR29vZC5HYW1lLlBvb2xlZC5QcmVkIDwtIGlmZWxzZShwcmVkaWN0KG1vZGVsX2dvb2RfcGxheWVyX3Bvb2xlZF9jdiwgdHlwZT0icmVzcG9uc2UiKT4wLjQ5LDEsMCkNCg0KI2xvb2tpbmcgYXQgc2Vuc2l0aXZpdHkgYW5kIHNwZWNpZmljaXR5DQp0YWJsZSh4PVExX2RhdGEkUGxheWVyLkdvb2QuR2FtZS5Qb29sZWQuUHJlZCwgeT1RMV9kYXRhJFBsYXllci5Hb29kLkdhbWUpDQpgYGANCg0KDQpgYGB7ciBjcm9zcyB2YWxpZGF0aW5nIHVucG9vbGVkIG1vZGVsIGZvciBnb29kIGdhbWVzfQ0Kc2V0LnNlZWQoMTIzKQ0KDQojbW9kZWwgdG8gYmUgdXNlZCBmb3IgY3Jvc3MgdmFsaWRhdGlvbg0KbW9kZWxfZ29vZF9wbGF5ZXJfdW5wb29sZWRfY3YgPC0gZ2xtZXIoUGxheWVyLkdvb2QuR2FtZX5DaGFuZ2UuUGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLiArIChDaGFuZ2UuUGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLnxhbm9uX2lkKSwgZGF0YT1RMV9kYXRhLCBmYW1pbHkgPSAiYmlub21pYWwiKQ0KDQoNCiNRMV9kYXRhJFBsYXllci5Hb29kLkdhbWUuVW5wb29sZWQuUHJlZCA8LSBwcmVkaWN0KG1vZGVsX2dvb2RfcGxheWVyX3VucG9vbGVkX2N2LCB0eXBlPSJyZXNwb25zZSIpDQoNCiNwcmVkIDwtIHByZWRpY3Rpb24ocHJlZGljdGlvbnMgPSBRMV9kYXRhJFBsYXllci5Hb29kLkdhbWUuVW5wb29sZWQuUHJlZCwNCiMgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gUTFfZGF0YSRQbGF5ZXIuR29vZC5HYW1lKQ0KI3BlcmYgPC0gcGVyZm9ybWFuY2UocHJlZCxtZWFzdXJlPSd0bnInLHgubWVhc3VyZT0ndHByJykNCiNwbG90KHBlcmYsIGNvbG9yaXplPVRSVUUpDQojYWJsaW5lKGE9MCwgYj0xKQ0KDQoNCiNtYWtpbmcgY29zdCBmdW5jdGlvbiBmb3IgY3Jvc3MgdmFsaWRhdGlvbiBmb3IgdW5wb29sZWQgbW9kZWwNCmNvc3QgPC0gZnVuY3Rpb24oeSwgeWhhdCl7DQogIG1lYW4oKCh5aGF0IDw9IDAuNDYpICYgeT09MSkgfCAoKHloYXQgPiAwLjQ2KSAmIHk9PTApKQ0KfQ0KDQoNCiNjcm9zcyB2YWxpZGF0aW5nIHRoZSB1bnBvb2xlZCBtb2RlbA0Kc3VtbWFyeShjdihtb2RlbF9nb29kX3BsYXllcl91bnBvb2xlZF9jdiwgaz01LCBjbHVzdGVyVmFyaWFibGVzID0gImFub25faWQiLCBzZWVkPTEyMywgY3JpdGVyaW9uPWNvc3QpKQ0KDQoNClExX2RhdGEkUGxheWVyLkdvb2QuR2FtZS5VbnBvb2xlZC5QcmVkIDwtIGlmZWxzZShwcmVkaWN0KG1vZGVsX2dvb2RfcGxheWVyX3VucG9vbGVkX2N2LCB0eXBlPSJyZXNwb25zZSIpPjAuNDYsMSwwKQ0KDQojbG9va2luZyBhdCBzZW5zaXRpdml0eSBhbmQgc3BlY2lmaWNpdHkNCnRhYmxlKHg9UTFfZGF0YSRQbGF5ZXIuR29vZC5HYW1lLlVucG9vbGVkLlByZWQsIHk9UTFfZGF0YSRQbGF5ZXIuR29vZC5HYW1lKQ0KYGBgDQoNCg0KDQpgYGB7ciBjcm9zcyB2YWxpZGF0aW5nIHVucG9vbGVkIG1vZGVsIGZvciBiYWQgZ2FtZXN9DQpzZXQuc2VlZCgxMjMpDQoNCiNtb2RlbCB0byBiZSB1c2VkIGZvciBjcm9zcyB2YWxpZGF0aW9uDQptb2RlbF9iYWRfcGxheWVyX3VucG9vbGVkX2N2IDwtIGdsbWVyKFBsYXllci5CYWQuR2FtZX5DaGFuZ2UuUGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLiArICgxfGFub25faWQpICsgKDArQ2hhbmdlLlBsYXllci5BdmVyYWdlLlJTSS4ubS5wZXIucy58YW5vbl9pZCksIGRhdGE9UTFfZGF0YSwgZmFtaWx5ID0gImJpbm9taWFsIikNCg0KI1ExX2RhdGEkUGxheWVyLkJhZC5HYW1lLlVucG9vbGVkLlByZWQgPC0gcHJlZGljdChtb2RlbF9iYWRfcGxheWVyX3VucG9vbGVkX2N2LCB0eXBlPSJyZXNwb25zZSIpDQoNCiNwcmVkIDwtIHByZWRpY3Rpb24ocHJlZGljdGlvbnMgPSBRMV9kYXRhJFBsYXllci5CYWQuR2FtZS5VbnBvb2xlZC5QcmVkLA0KIyAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBRMV9kYXRhJFBsYXllci5CYWQuR2FtZSkNCiNwZXJmIDwtIHBlcmZvcm1hbmNlKHByZWQsbWVhc3VyZT0ndG5yJyx4Lm1lYXN1cmU9J3RwcicpDQojcGxvdChwZXJmLCBjb2xvcml6ZT1UUlVFKQ0KI2FibGluZShhPTAsIGI9MSkNCg0KDQojbWFraW5nIGNvc3QgZnVuY3Rpb24gZm9yIGNyb3NzIHZhbGlkYXRpb24gZm9yIHVucG9vbGVkIG1vZGVsDQpjb3N0IDwtIGZ1bmN0aW9uKHksIHloYXQpew0KICBtZWFuKCh5aGF0IDw9LjA1KSAmIHk9PTEgfCAoeWhhdCA+IDAuMDUpICYgeT09MCkNCn0NCg0Kc3VtbWFyeShjdihtb2RlbF9iYWRfcGxheWVyX3VucG9vbGVkX2N2LCBrPTUsIGNsdXN0ZXJWYXJpYWJsZXMgPSAiYW5vbl9pZCIsIHNlZWQ9MTIzLCBjcml0ZXJpb249Y29zdCkpDQoNClExX2RhdGEkUGxheWVyLkJhZC5HYW1lLlVucG9vbGVkLlByZWQgPC0gaWZlbHNlKHByZWRpY3QobW9kZWxfYmFkX3BsYXllcl91bnBvb2xlZF9jdiwgdHlwZT0icmVzcG9uc2UiKT4wLjA1LDEsMCkNCg0KI2xvb2tpbmcgYXQgc2Vuc2l0aXZpdHkgYW5kIHNwZWNpZmljaXR5DQp0YWJsZSh4PVExX2RhdGEkUGxheWVyLkJhZC5HYW1lLlVucG9vbGVkLlByZWQsIHk9UTFfZGF0YSRQbGF5ZXIuQmFkLkdhbWUpDQpgYGANCg0KDQoNCmBgYHtyIGNyb3NzIHZhbGlkYXRpbmcgcG9vbGVkIG1vZGVsIGZvciBiYWQgZ2FtZXN9DQpzZXQuc2VlZCgxMjMpDQoNCiNtb2RlbCB0byBiZSB1c2VkIGZvciBjcm9zcyB2YWxpZGF0aW9uDQptb2RlbF9iYWRfcGxheWVyX2N2IDwtIGdsbShQbGF5ZXIuQmFkLkdhbWUgfiBDaGFuZ2UuUGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLiwgZGF0YT1RMV9kYXRhLCBmYW1pbHk9ImJpbm9taWFsIikNCg0KI1ExX2RhdGEkUGxheWVyLkJhZC5HYW1lLlBvb2xlZC5QcmVkIDwtIHByZWRpY3QobW9kZWxfYmFkX3BsYXllcl9jdiwgdHlwZT0icmVzcG9uc2UiKQ0KDQojcHJlZCA8LSBwcmVkaWN0aW9uKHByZWRpY3Rpb25zID0gUTFfZGF0YSRQbGF5ZXIuQmFkLkdhbWUuUG9vbGVkLlByZWQsDQojICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IFExX2RhdGEkUGxheWVyLkJhZC5HYW1lKQ0KI3BlcmYgPC0gcGVyZm9ybWFuY2UocHJlZCxtZWFzdXJlPSd0bnInLHgubWVhc3VyZT0ndHByJykNCiNwbG90KHBlcmYsIGNvbG9yaXplPVRSVUUpDQojYWJsaW5lKGE9MCwgYj0xKQ0KDQpjb3N0IDwtIGZ1bmN0aW9uKG9icywgcHJlZCl7DQogIG1lYW4oKHByZWQgPD0uMDMpICYgb2JzPT0xIHwgKHByZWQgPiAwLjAzKSAmIG9icz09MCkNCn0NCg0KI2Nyb3NzIHZhbGlkYXRpbmcgbW9kZWwNCmJhZF9wbGF5ZXJfY3YgPC0gY3YuZ2xtKGRhdGE9UTFfZGF0YSxnbG1maXQ9bW9kZWxfYmFkX3BsYXllcl9jdixjb3N0LEs9NSkNCg0KI2V4dHJhY3QgYXZlcmFnZSBlcnJvcg0KYmFkX3RlYW1fY3YkZGVsdGFbMV0NCg0KUTFfZGF0YSRQbGF5ZXIuQmFkLkdhbWUuUG9vbGVkLlByZWQgPC0gaWZfZWxzZShwcmVkaWN0KG1vZGVsX2JhZF9wbGF5ZXJfY3YsIHR5cGU9InJlc3BvbnNlIik+MC4wMywxLDApDQoNCiNsb29raW5nIGF0IHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eQ0KdGFibGUoeD1RMV9kYXRhJFBsYXllci5CYWQuR2FtZS5Qb29sZWQuUHJlZCwgeT1RMV9kYXRhJFBsYXllci5CYWQuR2FtZSkNCg0KYGBgDQpgYGB7ciBtYWtpbmcgZGF0YSBmcmFtZSBvZiBlcnJvcnMgZm9yIGVhY2ggbW9kZWwgdG8gY29tcGFyZSBlYXNpbHl9DQplcnJvcnMgPC0gZGF0YS5mcmFtZShNb2RlbCA9IGMoIkdvb2QtR2FtZXMtUG9vbGVkIiwgIkdvb2QtR2FtZXMtVW5wb29sZWQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCYWQtR2FtZXMtUG9vbGVkIiwgIkJhZC1HYW1lcy1VbnBvb2xlZCIpLA0KICAgICAgICAgICAgICAgICAgICAgQ0VSID0gYygwLjQ1MDM4MTcsIDAuMzc0MDQ1OAksIDAuMDMwNTM0MzUsIDAuMjgyNDQyNyksDQogICAgICAgICAgICAgICAgICAgICBDRVIuQ1YgPSBjKDAuNDgzNzQ3NiwgMC40NTY5NzksIDAuMjA0NTg4OSwgMC4wMzI1MDQ3OCksDQogICAgICAgICAgICAgICAgICAgICBDbGFzc2lmaWNhdGlvbi5UaHJlc2hvbGQgPSBjKDAuNDksIDAuNDYsIDAuMDMsIDAuMDUpKQ0KDQprYWJsZShlcnJvcnMpDQpgYGANCg0KQmFzZWQgb24gdGhlIGVycm9ycyB0aGF0IGNvbWUgZnJvbSB0aGUgY3Jvc3MgdmFsaWRhdGlvbiBvZiBhbGwgb2YgdGhlIG1vZGVscywgd2UgY2FuIHNlZSB0aGF0IHRoZSB1bnBvb2xlZCBtb2RlbHMgb3V0cGVyZm9ybSB0aGUgcG9vbGVkIG1vZGVscy4gQnkgZml0dGluZyBhIHVuaXF1ZSBtb2RlbCB0byBlYWNoIHBsYXllciB3ZSB3ZXJlIGFibGUgdG8gZ2V0IGJldHRlciBwcmVkaWN0aW9ucyBmb3IgaW4gZ2FtZSBzdWNjZXNzIHRoYW4gZml0dGluZyBhIGNvbW1vbiBtb2RlbCB0byBhbGwgb2YgdGhlIHBsYXllcnMuIFRoaXMgc3VnZ2VzdHMgdGhhdCBSU0kgbWF5IGhhdmUgZGlmZmVyaW5nIHByZWRpY3RpdmUgcG93ZXIgZm9yIGluIGdhbWUgcGVyZm9ybWFuY2UgZm9yIGVhY2ggcGxheWVyLiBUaGlzIG1lYW5zIHRoYXQgY2hhbmdlcyBpbiBSU0kgbWF5IGJlIGEgbW9yZSBwb3dlcmZ1bCBwcmVkaWN0b3IgZm9yIGluIGdhbWUgc3VjY2VzcyB0aGFuIGZvciBvdGhlciBhdGhsZXRlcyBvbiB0aGUgdGVhbS4gVGhpcyBhbHNvIHN1Z2dlc3RzIHRoYXQgc29tZSBpbmZvcm1hdGlvbiBtYXkgYmUgbG9zdCB3aGVuIGF2ZXJhZ2luZyBjaGFuZ2VzIGluIFJTSSBmb3IgdGhlIHRlYW0uIA0KT25lIHRoaW5nIHRvIG5vdGUgYWJvdXQgdGhlc2UgbW9kZWxzIGlzIHRoYXQgdGhlIG1ldHJpY3Mgc2hvd24gYWJvdmUgYXJlIHByZWRpY3RlZCByYXRlcyBpbiB3aGljaCB0aGUgbW9kZWwgd2lsbCBtYWtlIGEgd3JvbmcgcHJlZGljdGlvbi4gSXQncyBpbXBvcnRhbnQgdG8ga25vdyB0aGF0IGVhY2ggbW9kZWwgZ2l2ZXMgdGhlIHByZWRpY3RlZCBwcm9iYWJpbGl0eSB0aGF0IHRoZSBnaXZlbiBvYnNlcnZhdGlvbiBpcyBhICJnb29kIGdhbWUiIGZvciB0aGUgZmlyc3QgdHdvIG1vZGVscyBvciB0aGUgcHJvYmFiaWxpdHkgdGhhdCBhIGdpdmVuIG9ic2VydmF0aW9uIGlzIGEgImJhZCBnYW1lIiBmb3IgdGhlIGxhc3QgdHdvIG1vZGVscy4gTm9ybWFsbHkgdGhlIHRocmVzaG9sZCB0byBjb25zaWRlciBhIHByZWRpY3Rpb24gdG8gYmUgYSAxIG9yIGEgMCBpcyBpZiB0aGUgcHJvYmFiaWxpdHkgaXMgYWJvdmUgb3IgYmVsb3cgMC41IChyb3VuZGVkIHRvIHRoZSBuZWFyZXN0IHdob2xlIG51bWJlcikuIFRoZXNlIG1vZGVscyB3ZXJlIGdpdmVuIGRpZmZlcmVudCBjbGFzc2lmaWNhdGlvbiB0aHJlc2hvbGRzLiBUaGlzIHdhcyBmb3IgY29tcHV0YXRpb25hbCByZWFzb25zIHNpbmNlICJiYWQgZ2FtZXMiIGZvciBwbGF5ZXJzIGFyZSB2ZXJ5IHJhcmUgYW5kIHdpbGwgdGhlcmVmb3JlIGJlIGhhcmRlciB0byBpZGVudGlmeS4gDQpGb3IgdGhlIG1vZGVscyB0aGF0IGFyZSBwcmVkaWN0aW5nIHdoZXRoZXIgYSBnYW1lIHdpbGwgYmUgYSAiZ29vZCBnYW1lIiBvciBub3QsIHRoZXkgZG9uJ3QgaGF2ZSBhIGxvdCBvZiBwcmVkaWN0aXZlIHBvd2VyLiANCg0KDQoNCiMjIFF1ZXN0aW9uIDM6DQoNCiMjIyBJcyB0aGUgcHJldmlvdXMgd2VlaydzIGxvYWQgcmVsYXRlZCB0byBSU0k/DQoNCiMjIyMgUmVjYWxjdWxhdGluZyBHYW1lZGF5IE1pbnVzIENvbHVtbnMNCg0KYGBge3IgR2FtZWRheS5NaW51cy5OLkFjY2VsZXJhdGlvbi5Mb2FkfQ0KIyBSZWNhbGN1bGF0aW5nIHRoZSBHYW1lZGF5Lk1pbnVzLk4uQWNjZWxlcmF0aW9uLkxvYWQgQ29sdW1ucw0KDQojIENyZWF0ZSBhIGRmIHdpdGggcmVsZXZhbnQgY29sdW1ucyBhbmQgYWRkIGNvbHVtbiBzcGVjaWZ5aW5nIGlmIHRoYXQgZGF5IHdhcyBhIGdhbWUgb3Igbm90DQpkYWlseV9sb2FkIDwtIGtpbmV4b25fc2Vzc2lvbl9jbGVhbiB8Pg0KICBtdXRhdGUoR2FtZS5EYXkgPSBpZl9lbHNlKFR5cGUgPT0gIkdhbWUiLCAxLCAwKSkgfD4NCiAgZmlsdGVyKCFpcy5uYShEYWlseS5Ub3RhbC5BY2NlbC5Mb2FkLkFjY3VtKSkgfD4NCiAgc2VsZWN0KGFub25faWQsIERhdGUsIERhaWx5LlRvdGFsLkFjY2VsLkxvYWQuQWNjdW0sIEdhbWUuRGF5KSB8Pg0KICBhcnJhbmdlKGFub25faWQsIERhdGUpDQoNCiMgR2V0IGFsbCBnYW1lIGRheSBkYXRlcyBwZXIgcGxheWVyIGFzIGEgbG9va3VwIHRhYmxlDQpnYW1lX2RheXMgPC0gZGFpbHlfbG9hZCB8Pg0KICBmaWx0ZXIoR2FtZS5EYXkgPT0gMSkgfD4NCiAgc2VsZWN0KGFub25faWQsIEdhbWUuRGF0ZSA9IERhdGUpDQogICAgDQoNCiMgQWRkIGNvbHVtbiBEYXkuVHlwZSBmb3IgR0QtMSAtIEdELTQgYW5kIGdhbWVkYXlzDQpkYWlseV9sb2FkIDwtIGRhaWx5X2xvYWQgfD4NCiAgbGVmdF9qb2luKGdhbWVfZGF5cywgYnkgPSAiYW5vbl9pZCIsIHJlbGF0aW9uc2hpcCA9ICJtYW55LXRvLW1hbnkiKSB8Pg0KICBtdXRhdGUoDQogICAgRGF5cy5VbnRpbC5HYW1lID0gYXMubnVtZXJpYyhkaWZmdGltZShHYW1lLkRhdGUsIERhdGUsIHVuaXRzID0gImRheXMiKSksDQogICAgRGF5LlR5cGUgPSBjYXNlX3doZW4oDQogICAgICBEYXlzLlVudGlsLkdhbWUgPT0gMSB+ICJHRC0xIiwNCiAgICAgIERheXMuVW50aWwuR2FtZSA9PSAyIH4gIkdELTIiLA0KICAgICAgRGF5cy5VbnRpbC5HYW1lID09IDMgfiAiR0QtMyIsDQogICAgICBEYXlzLlVudGlsLkdhbWUgPT0gNCB+ICJHRC00IiwNCiAgICAgIEdhbWUuRGF5ID09IDEgfiAiR2FtZURheSIsDQogICAgICBUUlVFIH4gTkFfY2hhcmFjdGVyXw0KICAgICkNCiAgKSB8Pg0KICBmaWx0ZXIoIWlzLm5hKERheS5UeXBlKSkgfD4gICAgIyBrZWVwIG9ubHkgcm93cyB3aXRoaW4gNCBkYXlzIGJlZm9yZSBnYW1lDQogIHNlbGVjdCgtR2FtZS5EYXRlLCAtRGF5cy5VbnRpbC5HYW1lKQ0KDQojIEFkZCBjb2x1bW5zIGZvciBHYW1lZGF5Lk1pbnVzLk4uQWNjZWxlcmF0aW9uLkxvYWQNCkdhbWVkYXlfTWludXMgPC0gZGFpbHlfbG9hZCB8Pg0KICBtdXRhdGUoDQogICAgR2FtZWRheS5NaW51cy4xLkFjY2VsZXJhdGlvbi5Mb2FkID0gaWZfZWxzZShEYXkuVHlwZSA9PSAiR0QtMSIsIERhaWx5LlRvdGFsLkFjY2VsLkxvYWQuQWNjdW0sIE5BX3JlYWxfKSwNCiAgICBHYW1lZGF5Lk1pbnVzLjIuQWNjZWxlcmF0aW9uLkxvYWQgPSBpZl9lbHNlKERheS5UeXBlID09ICJHRC0yIiwgRGFpbHkuVG90YWwuQWNjZWwuTG9hZC5BY2N1bSwgTkFfcmVhbF8pLA0KICAgIEdhbWVkYXkuTWludXMuMy5BY2NlbGVyYXRpb24uTG9hZCA9IGlmX2Vsc2UoRGF5LlR5cGUgPT0gIkdELTMiLCBEYWlseS5Ub3RhbC5BY2NlbC5Mb2FkLkFjY3VtLCBOQV9yZWFsXyksDQogICAgR2FtZWRheS5NaW51cy40LkFjY2VsZXJhdGlvbi5Mb2FkID0gaWZfZWxzZShEYXkuVHlwZSA9PSAiR0QtNCIsIERhaWx5LlRvdGFsLkFjY2VsLkxvYWQuQWNjdW0sIE5BX3JlYWxfKSwNCiAgICBHYW1lRGF5LkFjY2VsZXJhdGlvbi5Mb2FkID0gaWZfZWxzZShEYXkuVHlwZSA9PSAiR2FtZURheSIsIERhaWx5LlRvdGFsLkFjY2VsLkxvYWQuQWNjdW0sIE5BX3JlYWxfKQ0KICApDQoNCiMgRGVsZXRlIGR1cGxpY2F0ZSByb3dzDQpHYW1lZGF5X01pbnVzIDwtIEdhbWVkYXlfTWludXMgfD4NCiAgZGlzdGluY3QoKQ0KDQpgYGANCg0KYGBge3IgQXZlcmFnZS5HYW1lZGF5Lk1pbnVzLk4uQWNjZWxlcmF0aW9uLkxvYWR9DQojIENyZWF0ZSBjb2x1bW5zIGZvciBBdmVyYWdlLkdhbWVkYXkuTWludXMuTi5BY2NlbGVyYXRpb24uTG9hZA0KDQojIENhbGN1bGF0ZSBhbmQgYWRkIGNvbHVtbnMgZm9yIHJ1bm5pbmcgYXZlcmFnZXMNCkdhbWVkYXlfTWludXMgPC0gR2FtZWRheV9NaW51cyB8Pg0KICBhcnJhbmdlKGFub25faWQsIERhdGUpIHw+DQogIGdyb3VwX2J5KGFub25faWQpIHw+DQogIG11dGF0ZSgNCiAgICAjIEN1bXVsYXRpdmUgY291bnQgYW5kIHN1bSBmb3IgR0QtMQ0KICAgIGN1bV9jb3VudF9nZDEgPSBjdW1zdW0oIWlzLm5hKEdhbWVkYXkuTWludXMuMS5BY2NlbGVyYXRpb24uTG9hZCkpLA0KICAgIGN1bV9zdW1fZ2QxID0gY3Vtc3VtKHJlcGxhY2VfbmEoR2FtZWRheS5NaW51cy4xLkFjY2VsZXJhdGlvbi5Mb2FkLCAwKSksDQogICAgQXZlcmFnZS5HYW1lZGF5Lk1pbnVzLjEuQWNjZWxlcmF0aW9uLkxvYWQgPSBpZl9lbHNlKA0KICAgICAgY3VtX2NvdW50X2dkMSA+IDAsDQogICAgICBjdW1fc3VtX2dkMSAvIGN1bV9jb3VudF9nZDEsDQogICAgICBOQV9yZWFsXw0KICAgICksDQogICAgDQogICAgIyBDdW11bGF0aXZlIGNvdW50IGFuZCBzdW0gZm9yIEdELTINCiAgICBjdW1fY291bnRfZ2QyID0gY3Vtc3VtKCFpcy5uYShHYW1lZGF5Lk1pbnVzLjIuQWNjZWxlcmF0aW9uLkxvYWQpKSwNCiAgICBjdW1fc3VtX2dkMiA9IGN1bXN1bShyZXBsYWNlX25hKEdhbWVkYXkuTWludXMuMi5BY2NlbGVyYXRpb24uTG9hZCwgMCkpLA0KICAgIEF2ZXJhZ2UuR2FtZWRheS5NaW51cy4yLkFjY2VsZXJhdGlvbi5Mb2FkID0gaWZfZWxzZSgNCiAgICAgIGN1bV9jb3VudF9nZDIgPiAwLA0KICAgICAgY3VtX3N1bV9nZDIgLyBjdW1fY291bnRfZ2QyLA0KICAgICAgTkFfcmVhbF8NCiAgICApLA0KICAgIA0KICAgICMgQ3VtdWxhdGl2ZSBjb3VudCBhbmQgc3VtIGZvciBHRC0zDQogICAgY3VtX2NvdW50X2dkMyA9IGN1bXN1bSghaXMubmEoR2FtZWRheS5NaW51cy4zLkFjY2VsZXJhdGlvbi5Mb2FkKSksDQogICAgY3VtX3N1bV9nZDMgPSBjdW1zdW0ocmVwbGFjZV9uYShHYW1lZGF5Lk1pbnVzLjMuQWNjZWxlcmF0aW9uLkxvYWQsIDApKSwNCiAgICBBdmVyYWdlLkdhbWVkYXkuTWludXMuMy5BY2NlbGVyYXRpb24uTG9hZCA9IGlmX2Vsc2UoDQogICAgICBjdW1fY291bnRfZ2QzID4gMCwNCiAgICAgIGN1bV9zdW1fZ2QzIC8gY3VtX2NvdW50X2dkMywNCiAgICAgIE5BX3JlYWxfDQogICAgKSwNCiAgICANCiAgICAjIEN1bXVsYXRpdmUgY291bnQgYW5kIHN1bSBmb3IgR0QtNA0KICAgIGN1bV9jb3VudF9nZDQgPSBjdW1zdW0oIWlzLm5hKEdhbWVkYXkuTWludXMuNC5BY2NlbGVyYXRpb24uTG9hZCkpLA0KICAgIGN1bV9zdW1fZ2Q0ID0gY3Vtc3VtKHJlcGxhY2VfbmEoR2FtZWRheS5NaW51cy40LkFjY2VsZXJhdGlvbi5Mb2FkLCAwKSksDQogICAgQXZlcmFnZS5HYW1lZGF5Lk1pbnVzLjQuQWNjZWxlcmF0aW9uLkxvYWQgPSBpZl9lbHNlKA0KICAgICAgY3VtX2NvdW50X2dkNCA+IDAsDQogICAgICBjdW1fc3VtX2dkNCAvIGN1bV9jb3VudF9nZDQsDQogICAgICBOQV9yZWFsXw0KICAgICkNCiAgKSB8Pg0KICB1bmdyb3VwKCkgfD4NCiAgc2VsZWN0KC1zdGFydHNfd2l0aCgiY3VtX2NvdW50XyIpLCAtc3RhcnRzX3dpdGgoImN1bV9zdW1fIikpICMgY2xlYW4gdXAgY29sdW1ucw0KDQpgYGANCg0KYGBge3IgQXZlcmFnZS5HYW1lZGF5LkFjY2VsZXJhdGlvbi5Mb2FkfQ0KIyBDYWxjdWxhdGUgcnVubmluZyBhdmVyYWdlcyBvZiBHYW1lZGF5LkFjY2VsZXJhdGlvbi5Mb2FkIGFuZCBhZGQgY29sdW1uIEF2ZXJhZ2UuR2FtZWRheS5BY2NlbGVyYXRpb24uTG9hZA0KDQpHYW1lZGF5X01pbnVzIDwtIEdhbWVkYXlfTWludXMgfD4NCiAgYXJyYW5nZShhbm9uX2lkLCBEYXRlKSB8Pg0KICBncm91cF9ieShhbm9uX2lkKSB8Pg0KICBtdXRhdGUoDQogICAgY3VtX2NvdW50X2dkID0gY3Vtc3VtKCFpcy5uYShHYW1lRGF5LkFjY2VsZXJhdGlvbi5Mb2FkKSksDQogICAgY3VtX3N1bV9nZCA9IGN1bXN1bShyZXBsYWNlX25hKEdhbWVEYXkuQWNjZWxlcmF0aW9uLkxvYWQsIDApKSwNCiAgICBBdmVyYWdlLkdhbWVEYXkuQWNjZWxlcmF0aW9uLkxvYWQgPSBpZl9lbHNlKA0KICAgICAgY3VtX2NvdW50X2dkID4gMCwNCiAgICAgIGN1bV9zdW1fZ2QgLyBjdW1fY291bnRfZ2QsDQogICAgICBOQV9yZWFsXw0KICAgICkNCiAgKSB8Pg0KICB1bmdyb3VwKCkgfD4NCiAgc2VsZWN0KC1jdW1fY291bnRfZ2QsIC1jdW1fc3VtX2dkKSAjIGNsZWFuIHVwIGNvbHVtbnMNCg0KYGBgDQoNCg0KIyBDYWxjdWxhdGUgbG9hZCBvZiA3LCAzLCBhbmQgMSwgZGF5IGJlZm9yZSB0ZXN0IGRheSBpbmNsdWRpbmcgdGVzdCBkYXRlLg0KDQoNCmBgYHtyIExvYWQgdnMuIFJTSX0NCiMgRmlsdGVyIHRvIG9ubHkgaGF2ZSBkYXRhIGZyb20gdGhpcyBzZWFzb24NClJTSSA8LSBWQUxEX0ZvcmNlRGVja3NfY2xlYW4gfD4NCiAgZmlsdGVyKERhdGUgPj0gYXMuRGF0ZSgiMjAyNC0xMC0xMCIpKSB8Pg0KICBzZWxlY3QoYW5vbl9pZCwgRGF0ZSwgUlNJLi5tLnBlci5zLiwgVHJpYWwpIHw+DQogIGFycmFuZ2UoYW5vbl9pZCwgRGF0ZSkgfD4NCiAgZ3JvdXBfYnkoYW5vbl9pZCwgRGF0ZSkgfD4NCiAgbXV0YXRlKERhaWx5LkF2Zy5SU0kuLm0ucGVyLnMgPSBtZWFuKFJTSS4ubS5wZXIucy4pKSB8Pg0KICB1bmdyb3VwKCkNCg0KDQojIFBsb3QgUlNJIG92ZXIgc2Vhc29uDQpnZ3Bsb3QoUlNJLCBhZXMoeD1EYXRlLCB5PURhaWx5LkF2Zy5SU0kuLm0ucGVyLnMsIGNvbG9yPWFub25faWQpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLCBzZT1GQUxTRSkgKw0KICBsYWJzKHRpdGxlID0gIkF0aGxldGUgUlNJIFNjb3JlcyBUaHJvdWdob3V0IFNlYXNvbiIpICsNCiAgdGhlbWVfY2xhc3NpYygpDQoNCg0KIyBDcmVhdGUgbG9hZCBkYXRhIGZyYW1lIGNvbnRhaW5pbmcgY29sdW1ucyByZWxldmFudCB0byBsb2FkDQpsb2FkIDwtIGtpbmV4b25fc2Vzc2lvbl9jbGVhbiB8Pg0KICBmaWx0ZXIoRGF0ZSA+PSBhcy5EYXRlKCIyMDI0LTEwLTEwIikpIHw+DQogIHNlbGVjdChhbm9uX2lkLCBEYXRlLCBEYWlseS5Ub3RhbC5BY2NlbC5Mb2FkLkFjY3VtLCBKdW1wLkxvYWQpIHw+DQogIGZpbHRlcighaXMubmEoRGFpbHkuVG90YWwuQWNjZWwuTG9hZC5BY2N1bSkpDQoNCg0KIyBMb29rIGludG8gRGFpbHkgQWNjZWxlcmF0aW9uIExvYWQgZm9yIG9uZSBhdGhsZXRlDQppZF80MF9sb2FkIDwtIGxvYWQgfD4NCiAgZmlsdGVyKGFub25faWQgPT0gIklEXzQwIikNCiMgUGxvdCBvZiBJRF80MCdzIERhaWx5IEFjY2VsIExvYWQNCmdncGxvdChkYXRhID0gaWRfNDBfbG9hZCwgYWVzKHggPSBEYXRlLCB5ID0gRGFpbHkuVG90YWwuQWNjZWwuTG9hZC5BY2N1bSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBsYWJzKHRpdGxlID0gIklEXzQwIERhaWx5IEFjY2VsZXJhdGlvbiBMb2FkIikgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KDQojIFBsb3Qgb2YgYWxsIGF0aGxldGUncyBkYWlseSBhY2NlbCBsb2FkIHRocm91Z2hvdXQgc2Vhc29uDQpnZ3Bsb3QoZGF0YSA9IGxvYWQsIGFlcyh4PURhdGUsIHk9RGFpbHkuVG90YWwuQWNjZWwuTG9hZC5BY2N1bSwgY29sb3I9YW5vbl9pZCkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkgKw0KICBsYWJzKHRpdGxlID0gIjIwMjQtMjUgQmFza3RlYmFsbCBBdGhsZXRlJ3MgRGFpbHkgQWNjZWxlcmF0aW9uIExvYWQiKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQoNCiMgUGxvdCBvZiBhbGwgYXRobGV0ZSdzIGRhaWx5IGp1bXAgbG9hZCB0aHJvdWdob3V0IHNlYXNvbg0KZ2dwbG90KGRhdGEgPSBsb2FkLCBhZXMoeD1EYXRlLCB5PUp1bXAuTG9hZCwgY29sb3I9YW5vbl9pZCkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkgKw0KICBsYWJzKHRpdGxlID0gIjIwMjQtMjUgQmFza3RlYmFsbCBBdGhsZXRlJ3MgRGFpbHkgSnVtcCBMb2FkIikgKw0KICB0aGVtZV9jbGFzc2ljKCkNCmBgYA0KVGhlIGdyYXBocyBzZWVtIHRvIHNob3cgdGhhdCBmb3IgbW9zdCBhdGhsZXRlcywgUlNJIHNjb3JlcyBpbmNyZWFzZWQgdGhyb3VnaG91dCB0aGUgc2Vhc29uLCB3aGlsZSBkYWlseSBhY2NlbGVyYXRpb24gbG9hZCBkZWNyZWFzZWQgYW5kIGp1bXAgbG9hZCBhYm91dCBzdGF5ZWQgdGhlIHNhbWUuDQoNCg0KYGBge3IgQ2FsY3VsYXRpbmcgbGFzdCA3LCAzLCBhbmQgMiBkYXkgbG9hZHN9DQojIENhbGN1bGF0ZSB0aGUgYXZlcmFnZSBhbmQgdG90YWwgYWNjZWxlcmF0aW9uIGFuZCBqdW1wIGxvYWQgaW4gdGhlIGxhc3QgNywgMywgYW5kIDIgZGF5cy4NCg0KIyMgTGFzdCA3IGRheXMgbm90IGxhc3QgNyBzZXNzaW9ucw0KIyBJbmNsdWRlIHRoYXQgZGF5IGluIHRoZSBsYXN0IDcuIChUaGF0IGRheSBhbmQgdGhlIDYgZGF5cyBiZWZvcmUgdGhhdCBkYXksIHRvdGFsIG9mIDcpDQpyb2xsaW5nX05EYXlfbG9hZCA8LSBsb2FkIHw+DQogIGZpbHRlcighaXMubmEoRGFpbHkuVG90YWwuQWNjZWwuTG9hZC5BY2N1bSkpIHw+DQogIGFycmFuZ2UoYW5vbl9pZCwgRGF0ZSkgfD4NCiAgZ3JvdXBfYnkoYW5vbl9pZCkgfD4NCiAgZ3JvdXBfc3BsaXQoKSB8Pg0KICBtYXBfZGZyKH57DQogICAgYXRobGV0ZV9kYXRhIDwtIC4NCiAgICBtYXBfZGZyKHNlcV9sZW4obnJvdyhhdGhsZXRlX2RhdGEpKSwgZnVuY3Rpb24oaSkgew0KICAgICAgY3VycmVudF9yb3cgPC0gYXRobGV0ZV9kYXRhW2ksIF0NCiAgICAgIHBhc3Rfd2VlayA8LSBhdGhsZXRlX2RhdGEgfD4NCiAgICAgICAgZmlsdGVyKERhdGUgPD0gY3VycmVudF9yb3ckRGF0ZSAmIERhdGUgPiBjdXJyZW50X3JvdyREYXRlIC0gZGF5cyg3KSkgIyAoPD0pIGluY2x1ZGVzIHRoYXQgZGF5IGluIHRoZSBsYXN0IDcuDQogICAgICANCiAgICAgIGN1cnJlbnRfcm93IHw+DQogICAgICAgIG11dGF0ZSgNCiAgICAgICAgICBBdmcuLjdEYXkuLkFjY2VsLkxvYWQgPSBtZWFuKHBhc3Rfd2VlayREYWlseS5Ub3RhbC5BY2NlbC5Mb2FkLkFjY3VtLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgIFRvdGFsLi43RGF5Li5BY2NlbC5Mb2FkID0gc3VtKHBhc3Rfd2VlayREYWlseS5Ub3RhbC5BY2NlbC5Mb2FkLkFjY3VtLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgIEF2Zy4uN0RheS4uSnVtcC5Mb2FkID0gbWVhbihwYXN0X3dlZWskSnVtcC5Mb2FkLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgIFRvdGFsLi43RGF5Li5KdW1wLkxvYWQgPSBzdW0ocGFzdF93ZWVrJEp1bXAuTG9hZCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICBEYXlzLlVzZWQuN0RheSA9IG5yb3cocGFzdF93ZWVrKQ0KICAgICAgICApDQogICAgfSkNCiAgfSkNCg0KDQoNCiMgQWRkIDMgRGF5IExvYWQNCiMgVGhhdCBkYXkgYW5kIHRoZSB0d28gZGF5cyBiZWZvcmUgaXQNCnJvbGxpbmdfTkRheV9sb2FkIDwtIHJvbGxpbmdfTkRheV9sb2FkIHw+DQogIGFycmFuZ2UoYW5vbl9pZCwgRGF0ZSkgfD4NCiAgZ3JvdXBfYnkoYW5vbl9pZCkgfD4NCiAgZ3JvdXBfc3BsaXQoKSB8Pg0KICBtYXBfZGZyKH57DQogICAgYXRobGV0ZV9kYXRhIDwtIC4NCiAgICBtYXBfZGZyKHNlcV9sZW4obnJvdyhhdGhsZXRlX2RhdGEpKSwgZnVuY3Rpb24oaSkgew0KICAgICAgY3VycmVudF9yb3cgPC0gYXRobGV0ZV9kYXRhW2ksIF0NCiAgICAgIHBhc3RfM2RheXMgPC0gYXRobGV0ZV9kYXRhIHw+DQogICAgICAgIGZpbHRlcihEYXRlIDw9IGN1cnJlbnRfcm93JERhdGUgJiBEYXRlID4gY3VycmVudF9yb3ckRGF0ZSAtIGRheXMoMykpICAjIGluY2x1ZGVzIGN1cnJlbnQgZGF5DQoNCiAgICAgIGN1cnJlbnRfcm93IHw+DQogICAgICAgIG11dGF0ZSgNCiAgICAgICAgICBBdmcuLjNEYXkuLkFjY2VsLkxvYWQgPSBtZWFuKHBhc3RfM2RheXMkRGFpbHkuVG90YWwuQWNjZWwuTG9hZC5BY2N1bSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICBUb3RhbC4uM0RheS4uQWNjZWwuTG9hZCA9IHN1bShwYXN0XzNkYXlzJERhaWx5LlRvdGFsLkFjY2VsLkxvYWQuQWNjdW0sIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgQXZnLi4zRGF5Li5KdW1wLkxvYWQgPSBtZWFuKHBhc3RfM2RheXMkSnVtcC5Mb2FkLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgIFRvdGFsLi4zRGF5Li5KdW1wLkxvYWQgPSBzdW0ocGFzdF8zZGF5cyRKdW1wLkxvYWQsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgRGF5cy5Vc2VkLjNEYXkgPSBucm93KHBhc3RfM2RheXMpDQogICAgICAgICkNCiAgICB9KQ0KICB9KQ0KDQoNCg0KIyBBZGQgMiBEYXkgTG9hZA0KIyBUaGF0IGRheSBhbmQgdGhlIGRheSBiZWZvcmUgaXQNCnJvbGxpbmdfTkRheV9sb2FkIDwtIHJvbGxpbmdfTkRheV9sb2FkIHw+DQogIGFycmFuZ2UoYW5vbl9pZCwgRGF0ZSkgfD4NCiAgZ3JvdXBfYnkoYW5vbl9pZCkgfD4NCiAgZ3JvdXBfc3BsaXQoKSB8Pg0KICBtYXBfZGZyKH57DQogICAgYXRobGV0ZV9kYXRhIDwtIC4NCiAgICBtYXBfZGZyKHNlcV9sZW4obnJvdyhhdGhsZXRlX2RhdGEpKSwgZnVuY3Rpb24oaSkgew0KICAgICAgY3VycmVudF9yb3cgPC0gYXRobGV0ZV9kYXRhW2ksIF0NCiAgICAgIHBhc3RfMmRheXMgPC0gYXRobGV0ZV9kYXRhIHw+DQogICAgICAgIGZpbHRlcihEYXRlIDw9IGN1cnJlbnRfcm93JERhdGUgJiBEYXRlID4gY3VycmVudF9yb3ckRGF0ZSAtIGRheXMoMikpICAjIGluY2x1ZGVzIGN1cnJlbnQgZGF5DQoNCiAgICAgIGN1cnJlbnRfcm93IHw+DQogICAgICAgIG11dGF0ZSgNCiAgICAgICAgICBBdmcuLjJEYXkuLkFjY2VsLkxvYWQgPSBtZWFuKHBhc3RfMmRheXMkRGFpbHkuVG90YWwuQWNjZWwuTG9hZC5BY2N1bSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICBUb3RhbC4uMkRheS4uQWNjZWwuTG9hZCA9IHN1bShwYXN0XzJkYXlzJERhaWx5LlRvdGFsLkFjY2VsLkxvYWQuQWNjdW0sIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgQXZnLi4yRGF5Li5KdW1wLkxvYWQgPSBtZWFuKHBhc3RfMmRheXMkSnVtcC5Mb2FkLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgIFRvdGFsLi4yRGF5Li5KdW1wLkxvYWQgPSBzdW0ocGFzdF8yZGF5cyRKdW1wLkxvYWQsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgRGF5cy5Vc2VkLjJEYXkgPSBucm93KHBhc3RfMmRheXMpDQogICAgICAgICkNCiAgICB9KQ0KICB9KQ0KDQpgYGANCg0KYGBge3IgbWVyZ2V9DQpSU0lfZGFpbHlfYXZnIDwtIFJTSSB8Pg0KICBkaXN0aW5jdChhbm9uX2lkLCBEYXRlLCBEYWlseS5BdmcuUlNJLi5tLnBlci5zKQ0KDQojIE1lcmdlIHRoZSBSU0kgYW5kIHJvbGxpbmcgZGF5IGxvYWQgZGF0YSBmcmFtZXMNCmxvYWRfYW5kX1JTSSA8LSBSU0lfZGFpbHlfYXZnIHw+DQogIGxlZnRfam9pbigNCiAgICByb2xsaW5nX05EYXlfbG9hZCwNCiAgICBieSA9ICJhbm9uX2lkIiwNCiAgICByZWxhdGlvbnNoaXAgPSAibWFueS10by1tYW55Ig0KICApIHw+DQogIGZpbHRlcihEYXRlLnkgPD0gRGF0ZS54ICYgRGF0ZS55ID49IERhdGUueCAtIGRheXMoNykpIHw+ICMgPD0gaW5jbHVkZXMgc2FtZSBkYXkuIE9uIGRheXMgd2hlbiBSU0kgYW5kIGFjY2VsIGxvYWQgYXJlIG1lYXN1cmVkLCBhY2NlbCBsb2FkIGlzIG1lYXN1cmVkIGZpcnN0LCBtZWFuaW5nIHdlIHNob3VsZCBpbmNsdWRlIGl0Lg0KICBncm91cF9ieShhbm9uX2lkLCBEYXRlLngpIHw+DQogIHNsaWNlX21heChEYXRlLnksIG4gPSAxKSB8PiAgIyBLZWVwIHRoZSBtb3N0IHJlY2VudCBsb2FkIGRhdGEgYmVmb3JlIFJTSQ0KICB1bmdyb3VwKCkgfD4NCiAgcmVuYW1lKA0KICAgIFJTSV9EYXRlID0gRGF0ZS54LA0KICAgIExvYWRfRGF0ZSA9IERhdGUueSwNCiAgICBSU0kgPSBEYWlseS5BdmcuUlNJLi5tLnBlci5zDQogICkNCg0KDQojIE5vdyB0aGF0IG9ubHkgaGF2ZSBsb2FkIGRhdGEgZm9yIE4gZGF5cyBiZWZvcmUgYSB0ZXN0IChhbmQgdGhhdCBkYXkpIHdlIHJlbmFtZSB0aGUgY29sdW1ucw0KbG9hZF9hbmRfUlNJIDwtIGxvYWRfYW5kX1JTSSB8PiByZW5hbWUoDQogIGBURC02Li5BdmcuLkFjY2VsLkxvYWRgID0gQXZnLi43RGF5Li5BY2NlbC5Mb2FkLA0KICBgVEQtNi4uVG90YWwuLkFjY2VsLkxvYWRgID0gVG90YWwuLjdEYXkuLkFjY2VsLkxvYWQsDQogIGBURC02Li5BdmcuLkp1bXAuTG9hZGAgPSBBdmcuLjdEYXkuLkp1bXAuTG9hZCwNCiAgYFRELTYuLlRvdGFsLi5KdW1wLkxvYWRgID0gVG90YWwuLjdEYXkuLkp1bXAuTG9hZCwNCg0KICBgVEQtMi4uQXZnLi5BY2NlbC5Mb2FkYCA9IEF2Zy4uM0RheS4uQWNjZWwuTG9hZCwNCiAgYFRELTIuLlRvdGFsLi5BY2NlbC5Mb2FkYCA9IFRvdGFsLi4zRGF5Li5BY2NlbC5Mb2FkLA0KICBgVEQtMi4uQXZnLi5KdW1wLkxvYWRgID0gQXZnLi4zRGF5Li5KdW1wLkxvYWQsDQogIGBURC0yLi5Ub3RhbC4uSnVtcC5Mb2FkYCA9IFRvdGFsLi4zRGF5Li5KdW1wLkxvYWQsDQoNCiAgYFRELTEuLkF2Zy4uQWNjZWwuTG9hZGAgPSBBdmcuLjJEYXkuLkFjY2VsLkxvYWQsDQogIGBURC0xLi5Ub3RhbC4uQWNjZWwuTG9hZGAgPSBUb3RhbC4uMkRheS4uQWNjZWwuTG9hZCwNCiAgYFRELTEuLkF2Zy4uSnVtcC5Mb2FkYCA9IEF2Zy4uMkRheS4uSnVtcC5Mb2FkLA0KICBgVEQtMS4uVG90YWwuLkp1bXAuTG9hZGAgPSBUb3RhbC4uMkRheS4uSnVtcC5Mb2FkDQopDQoNCiMgVEQtNiBtZWFucyB0aGUgbG9hZCBkYXRhIGZyb20gdGhlIGxhc3QgNiBkYXlzIGJlZm9yZSB0aGUgdGVzdCBkYXkgYW5kIHRoZSB0ZXN0IGRheQ0KIyAobG9hZCBkYXRhIGZyb20gdGhlIGxhc3QgNiBkYXlzIGFuZCB0aGUgdGVzdCBkYXkpDQojIFRELTIgbWVhbnMgdGhlIGxvYWQgZGF0YSBmcm9tIHRoZSB0d28gZGF5cyBwcmlvciB0byB0aGUgdGVzdCBkYXkgYW5kIHRoZSB0ZXN0IGRheQ0KIyBURC0xIG1lYW5zIHRoZSBkYXRhIGZyb20gdGhlIGRheSBiZWZvcmUgdGhlIHRlc3QgZGF5IGFuZCBkYXRhIGZyb20gdGhlIHRlc3QgZGF5DQoNCmBgYA0KDQoNCg0KYGBge3IgQ29ycmVsYXRpb24gdGVzdHN9DQojIENvcnJlbGF0aW9uIFRlc3RzIGZvciBlYWNoIHZhcmlhYmxlIHZzIFJTSQ0KDQojIERlZmluZSB0YXJnZXQgdmFyaWFibGVzDQpsb2FkX3ZhcnMgPC0gYygNCiAgIlRELTYuLkF2Zy4uQWNjZWwuTG9hZCIsICJURC02Li5Ub3RhbC4uQWNjZWwuTG9hZCIsDQogICJURC0yLi5BdmcuLkFjY2VsLkxvYWQiLCAiVEQtMi4uVG90YWwuLkFjY2VsLkxvYWQiLA0KICAiVEQtMS4uQXZnLi5BY2NlbC5Mb2FkIiwgIlRELTEuLlRvdGFsLi5BY2NlbC5Mb2FkIiwNCiAgIlRELTYuLkF2Zy4uSnVtcC5Mb2FkIiwgICJURC02Li5Ub3RhbC4uSnVtcC5Mb2FkIiwNCiAgIlRELTIuLkF2Zy4uSnVtcC5Mb2FkIiwgICJURC0yLi5Ub3RhbC4uSnVtcC5Mb2FkIiwNCiAgIlRELTEuLkF2Zy4uSnVtcC5Mb2FkIiwgICJURC0xLi5Ub3RhbC4uSnVtcC5Mb2FkIg0KKQ0KDQojIENvbXB1dGUgY29ycmVsYXRpb25zDQpjb3JyZWxhdGlvbl9yZXN1bHRzIDwtIG1hcF9kZnIobG9hZF92YXJzLCBmdW5jdGlvbih2YXIpIHsNCiAgcGVhcnNvbiA8LSBjb3IobG9hZF9hbmRfUlNJJFJTSSwgbG9hZF9hbmRfUlNJW1t2YXJdXSwgdXNlID0gImNvbXBsZXRlLm9icyIpDQogIHNwZWFybWFuIDwtIGNvcihsb2FkX2FuZF9SU0kkUlNJLCBsb2FkX2FuZF9SU0lbW3Zhcl1dLCBtZXRob2QgPSAic3BlYXJtYW4iLCB1c2UgPSAiY29tcGxldGUub2JzIikNCiAgDQogIHRpYmJsZSgNCiAgICBWYXJpYWJsZSA9IHZhciwNCiAgICBQZWFyc29uID0gcm91bmQocGVhcnNvbiwgMyksDQogICAgU3BlYXJtYW4gPSByb3VuZChzcGVhcm1hbiwgMykNCiAgKQ0KfSkNCg0KDQprYWJsZShjb3JyZWxhdGlvbl9yZXN1bHRzKQ0KDQpgYGANCg0KDQoNCg0KDQpgYGB7ciBQcmV2aW91cyBOIERheXMgQWNjZWwgTG9hZCB2cy4gUlNJfQ0KIyBBVkVSQUdFIEFDQ0VMIExPQUQ6DQojIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIFJTSSBhbmQgNy1EYXkgQXZlcmFnZSBBY2NlbGVyYXRpb24gTG9hZA0KZ2dwbG90KGxvYWRfYW5kX1JTSSwgYWVzKHggPSBgVEQtNi4uQXZnLi5BY2NlbC5Mb2FkYCwgeSA9IFJTSSkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICIjQ0ZCODdDIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlJTSSB2cy4gNy1EYXkgQXZnIEFjY2VsIExvYWQiLA0KICAgIHggPSAiNy1EYXkgQXZnIEFjY2VsIExvYWQgKFRELTYgdG8gVEQpIiwNCiAgICB5ID0gIlJTSSAobS9zKSINCiAgKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQojIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIFJTSSBhbmQgMy1EYXkgQXZlcmFnZSBBY2NlbGVyYXRpb24gTG9hZA0KZ2dwbG90KGxvYWRfYW5kX1JTSSwgYWVzKHggPSBgVEQtMi4uQXZnLi5BY2NlbC5Mb2FkYCwgeSA9IFJTSSkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICIjQ0ZCODdDIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlJTSSB2cy4gMy1EYXkgQXZnIEFjY2VsIExvYWQiLA0KICAgIHggPSAiMy1EYXkgQXZnIEFjY2VsIExvYWQgKFRELTIgdG8gVEQpIiwNCiAgICB5ID0gIlJTSSAobS9zKSINCiAgKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQojIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIFJTSSBhbmQgMi1EYXkgQXZlcmFnZSBBY2NlbGVyYXRpb24gTG9hZA0KZ2dwbG90KGxvYWRfYW5kX1JTSSwgYWVzKHggPSBgVEQtMS4uQXZnLi5BY2NlbC5Mb2FkYCwgeSA9IFJTSSkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICIjQ0ZCODdDIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlJTSSB2cy4gMi1EYXkgQXZnIEFjY2VsIExvYWQiLA0KICAgIHggPSAiMi1EYXkgQXZnIEFjY2VsIExvYWQgKFRELTEgdG8gVEQpIiwNCiAgICB5ID0gIlJTSSAobS9zKSINCiAgKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQoNCiMgVE9UQUwgQUNDRUwgTE9BRDoNCiMgUlNJIGFuZCA3LURheSBUb3RhbCBBY2NlbGVyYXRpb24gTG9hZA0KZ2dwbG90KGxvYWRfYW5kX1JTSSwgYWVzKHggPSBgVEQtNi4uVG90YWwuLkFjY2VsLkxvYWRgLCB5ID0gUlNJKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UsIGNvbG9yID0gIiNDRkI4N0MiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUlNJIHZzLiA3LURheSBBdmcgQWNjZWwgTG9hZCIsDQogICAgeCA9ICI3LURheSBUb3RhbCBBY2NlbCBMb2FkIChURC02IHRvIFREKSIsDQogICAgeSA9ICJSU0kgKG0vcykiDQogICkgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KDQojIFJTSSBhbmQgMy1EYXkgVG90YWwgQWNjZWxlcmF0aW9uIExvYWQNCmdncGxvdChsb2FkX2FuZF9SU0ksIGFlcyh4ID0gYFRELTIuLlRvdGFsLi5BY2NlbC5Mb2FkYCwgeSA9IFJTSSkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICIjQ0ZCODdDIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlJTSSB2cy4gMy1EYXkgQXZnIEFjY2VsIExvYWQiLA0KICAgIHggPSAiMy1EYXkgVG90YWwgQWNjZWwgTG9hZCAoVEQtMiB0byBURCkiLA0KICAgIHkgPSAiUlNJIChtL3MpIg0KICApICsNCiAgdGhlbWVfY2xhc3NpYygpDQoNCg0KIyBSU0kgYW5kIDItRGF5IEF2ZXJhZ2UgQWNjZWxlcmF0aW9uIExvYWQNCmdncGxvdChsb2FkX2FuZF9SU0ksIGFlcyh4ID0gYFRELTEuLlRvdGFsLi5BY2NlbC5Mb2FkYCwgeSA9IFJTSSkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICIjQ0ZCODdDIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlJTSSB2cy4gMi1EYXkgQXZnIEFjY2VsIExvYWQiLA0KICAgIHggPSAiMi1EYXkgVG90YWwgQWNjZWwgTG9hZCAoVEQtMSB0byBURCkiLA0KICAgIHkgPSAiUlNJIChtL3MpIg0KICApICsNCiAgdGhlbWVfY2xhc3NpYygpDQoNCmBgYA0KYGBge3IgUHJldmlvdXMgTiBEYXlzIEp1bXAgTG9hZCB2cy4gUlNJfQ0KIyBBVkVSQUdFIEpVTVAgTE9BRDoNCiMgUlNJIGFuZCA3LURheSBBdmVyYWdlIEp1bXAgTG9hZA0KZ2dwbG90KGxvYWRfYW5kX1JTSSwgYWVzKHggPSBgVEQtNi4uQXZnLi5KdW1wLkxvYWRgLCB5ID0gUlNJKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UsIGNvbG9yID0gIiNDRkI4N0MiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUlNJIHZzLiA3LURheSBBdmcgSnVtcCBMb2FkIiwNCiAgICB4ID0gIjctRGF5IEF2ZyBKdW1wIExvYWQgKFRELTYgdG8gVEQpIiwNCiAgICB5ID0gIlJTSSAobS9zKSINCiAgKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQojIFJTSSBhbmQgMy1EYXkgQXZlcmFnZSBKdW1wIExvYWQNCmdncGxvdChsb2FkX2FuZF9SU0ksIGFlcyh4ID0gYFRELTIuLkF2Zy4uSnVtcC5Mb2FkYCwgeSA9IFJTSSkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICIjQ0ZCODdDIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlJTSSB2cy4gMy1EYXkgQXZnIEp1bXAgTG9hZCIsDQogICAgeCA9ICIzLURheSBBdmcgSnVtcCBMb2FkIChURC0yIHRvIFREKSIsDQogICAgeSA9ICJSU0kgKG0vcykiDQogICkgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KIyBSU0kgYW5kIDItRGF5IEF2ZXJhZ2UgSnVtcCBMb2FkDQpnZ3Bsb3QobG9hZF9hbmRfUlNJLCBhZXMoeCA9IGBURC0xLi5BdmcuLkp1bXAuTG9hZGAsIHkgPSBSU0kpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiI0NGQjg3QyIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJSU0kgdnMuIDItRGF5IEF2ZyBKdW1wIExvYWQiLA0KICAgIHggPSAiMi1EYXkgQXZnIEp1bXAgTG9hZCAoVEQtMSB0byBURCkiLA0KICAgIHkgPSAiUlNJIChtL3MpIg0KICApICsNCiAgdGhlbWVfY2xhc3NpYygpDQoNCg0KIyBUT1RBTCBKVU1QIExPQUQ6DQojIFJTSSBhbmQgNy1EYXkgVG90YWwgSnVtcCBMb2FkDQpnZ3Bsb3QobG9hZF9hbmRfUlNJLCBhZXMoeCA9IGBURC02Li5Ub3RhbC4uSnVtcC5Mb2FkYCwgeSA9IFJTSSkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICIjQ0ZCODdDIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlJTSSB2cy4gNy1EYXkgQXZnIEp1bXAgTG9hZCIsDQogICAgeCA9ICI3LURheSBUb3RhbCBKdW1wIExvYWQgKFRELTYgdG8gVEQpIiwNCiAgICB5ID0gIlJTSSAobS9zKSINCiAgKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQoNCiMgUlNJIGFuZCAzLURheSBUb3RhbCBKdW1wIExvYWQNCmdncGxvdChsb2FkX2FuZF9SU0ksIGFlcyh4ID0gYFRELTIuLlRvdGFsLi5KdW1wLkxvYWRgLCB5ID0gUlNJKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UsIGNvbG9yID0gIiNDRkI4N0MiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUlNJIHZzLiAzLURheSBBdmcgSnVtcCBMb2FkIiwNCiAgICB4ID0gIjMtRGF5IFRvdGFsIEp1bXAgTG9hZCAoVEQtMiB0byBURCkiLA0KICAgIHkgPSAiUlNJIChtL3MpIg0KICApICsNCiAgdGhlbWVfY2xhc3NpYygpDQoNCg0KIyBSU0kgYW5kIDItRGF5IFRvdGFsIEp1bXAgTG9hZA0KZ2dwbG90KGxvYWRfYW5kX1JTSSwgYWVzKHggPSBgVEQtMS4uVG90YWwuLkp1bXAuTG9hZGAsIHkgPSBSU0kpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiI0NGQjg3QyIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJSU0kgdnMuIDItRGF5IEF2ZyBKdW1wIExvYWQiLA0KICAgIHggPSAiMi1EYXkgVG90YWwgSnVtcCBMb2FkIChURC0xIHRvIFREKSIsDQogICAgeSA9ICJSU0kgKG0vcykiDQogICkgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KYGBgDQoNCmBgYHtyfQ0KIyBQbG90IGZvciBlYWNoIGF0aGxldGUNCnVuaXF1ZV9pZHMgPC0gdW5pcXVlKGxvYWRfYW5kX1JTSSRhbm9uX2lkKQ0KDQpmb3IgKGlkIGluIHVuaXF1ZV9pZHMpIHsNCiAgcCA8LSBnZ3Bsb3QoZmlsdGVyKGxvYWRfYW5kX1JTSSwgYW5vbl9pZCA9PSBpZCksDQogICAgICAgICAgICAgIGFlcyh4ID0gYFRELTYuLkF2Zy4uQWNjZWwuTG9hZGAsIHkgPSBSU0kpKSArDQogICAgZ2VvbV9wb2ludCgpICsNCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBjb2xvciA9ICIjQ0ZCODdDIikgKw0KICAgIGxhYnModGl0bGUgPSBwYXN0ZSgiUlNJIHZzLiBQcmlvciBXZWVrJ3MgQWNjZWwgTG9hZDoiLCBpZCksDQogICAgICAgICB4ID0gIlRvdGFsIExvYWQgTGFzdCA3IERheXMiLA0KICAgICAgICAgeSA9ICJSU0kiKQ0KICAgcHJpbnQocCkNCiAgIA0KfQ0KDQpgYGANCg0KYGBge3IgQ29ycmVsYXRpb259DQojIENvcnJlbGF0aW9uIFRlc3RzIGZvciBlYWNoIHZhcmlhYmxlIHZzIFJTSQ0KDQojIENhbGN1bGF0ZSBvdmVyYWxsIFBlYXJzb24gY29ycmVsYXRpb25zIGZvciBlYWNoIHZhcmlhYmxlDQpvdmVyYWxsX2NvcnJzIDwtIG1hcF9kZnIobG9hZF92YXJzLCB+IHsNCiAgbG9hZF9hbmRfUlNJIHw+IA0KICAgIHN1bW1hcml6ZSgNCiAgICAgIHIgPSBjb3IoUlNJLCAuZGF0YVtbLnhdXSwgdXNlID0gImNvbXBsZXRlLm9icyIpLA0KICAgICAgbiA9IG4oKQ0KICAgICkgfD4gDQogICAgbXV0YXRlKHZhcmlhYmxlID0gLngpDQp9KQ0KDQojIEJhc2ljIHBsb3QgKG5vIHRoZW1pbmcpDQpnZ3Bsb3Qob3ZlcmFsbF9jb3JycywgYWVzKHggPSByZW9yZGVyKHZhcmlhYmxlLCByKSwgeSA9IHIpKSArDQogIGdlb21fY29sKGZpbGwgPSAiI0NGQjg3QyIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHIsIDIpKSwgDQogICAgICAgICAgICBoanVzdCA9IGlmZWxzZShvdmVyYWxsX2NvcnJzJHIgPj0gMCwgLTAuMSwgMS4xKSwNCiAgICAgICAgICAgIHNpemUgPSAzKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIGxhYnModGl0bGUgPSAiQ29ycmVsYXRpb24gQmV0d2VlbiBMb2FkIE1ldHJpY3MgYW5kIFJTSSIsDQogICAgICAgeCA9ICJMb2FkIE1ldHJpYyIsDQogICAgICAgeSA9ICJQZWFyc29uIENvcnJlbGF0aW9uIChyKSIpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBnc3ViKCJcXC5cXC4iLCAiOiAiLCB4KSkgKyAgIyBDbGVhbiBuYW1lcw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KDQpgYGANCkp1bXAgTG9hZCBzZWVtcyB0byBiZSBtb3JlIGNvcnJlbGF0ZWQgYW5kIGV2ZW4gcG9zaXRpdmVseSBjb3JyZWxhdGVkIHRoYW4gYWNjZWwgbG9hZC4NCg0KYGBge3IgUGVyIEF0aGxldGUgQWNjZWwgTG9hZCBDb3JyZWxhdGlvbnN9DQojIFBlciBhdGhsZXRlIGFjY2VsIGxvYWQgY29ycmVsYXRpb25zIHdpdGggUlNJDQoNCiMgQUNDRUwgTE9BRDoNCiMgQXZlcmFnZSA3IGRheSBhY2NlbCBsb2FkDQpwZXJfYXRobGV0ZV9jb3Jyc19hdmcgPC0gbG9hZF9hbmRfUlNJIHw+DQogIGdyb3VwX2J5KGFub25faWQpIHw+DQogIHN1bW1hcml6ZSgNCiAgICByID0gY29yKFJTSSwgYFRELTYuLkF2Zy4uQWNjZWwuTG9hZGAsIHVzZSA9ICJjb21wbGV0ZS5vYnMiKSwNCiAgICBuID0gbigpDQogICkgfD4NCiAgYXJyYW5nZShyKQ0KDQpnZ3Bsb3QocGVyX2F0aGxldGVfY29ycnNfYXZnLCBhZXMoeCA9IHJlb3JkZXIoYW5vbl9pZCwgciksIHkgPSByKSkgKw0KICBnZW9tX2NvbChmaWxsID0gIiNDRkI4N0MiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChyLCAyKSksIA0KICAgICAgICAgICAgICBoanVzdCA9IGlmZWxzZShwZXJfYXRobGV0ZV9jb3Jyc19hdmckciA+PSAwLCAtMC4xLCAxLjEpLA0KICAgICAgICAgICAgICBzaXplID0gMy4yLA0KICAgICAgICAgICAgICBjb2xvciA9ICIjMDAwMDAwIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHRpdGxlID0gIlBlciBBdGhsZXRlIENvcnJlbGF0aW9uIEJldHdlZW4gQXZnIDctRGF5IEFjY2VsIExvYWQgYW5kIFJTSSIsDQogICAgICAgeCA9ICJBdGhsZXRlIiwNCiAgICAgICB5ID0gIkNvcnJlbGF0aW9uIChyKSIpICsgDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQoNCiMgVG90YWwgNyBkYXkgYWNjZWwgbG9hZA0KcGVyX2F0aGxldGVfY29ycnNfdG90YWwgPC0gbG9hZF9hbmRfUlNJIHw+DQogIGdyb3VwX2J5KGFub25faWQpIHw+DQogIHN1bW1hcml6ZSgNCiAgICByID0gY29yKFJTSSwgYFRELTYuLlRvdGFsLi5BY2NlbC5Mb2FkYCwgdXNlID0gImNvbXBsZXRlLm9icyIpLA0KICAgIG4gPSBuKCkNCiAgKSB8Pg0KICBhcnJhbmdlKHIpDQoNCmdncGxvdChwZXJfYXRobGV0ZV9jb3Jyc190b3RhbCwgYWVzKHggPSByZW9yZGVyKGFub25faWQsIHIpLCB5ID0gcikpICsNCiAgZ2VvbV9jb2woZmlsbCA9ICIjQ0ZCODdDIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQociwgMikpLCANCiAgICAgICAgICAgICAgaGp1c3QgPSBpZmVsc2UocGVyX2F0aGxldGVfY29ycnNfdG90YWwkciA+PSAwLCAtMC4xLCAxLjEpLA0KICAgICAgICAgICAgICBzaXplID0gMy4yLA0KICAgICAgICAgICAgICBjb2xvciA9ICIjMDAwMDAwIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHRpdGxlID0gIlBlciBBdGhsZXRlIENvcnJlbGF0aW9uIEJldHdlZW4gVG90YWwgNy1EYXkgQWNjZWwgTG9hZCBhbmQgUlNJIiwNCiAgICAgICB4ID0gIkF0aGxldGUiLA0KICAgICAgIHkgPSAiQ29ycmVsYXRpb24gKHIpIikgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KDQoNCiMgQXZlcmFnZSAzIGRheSBhY2NlbCBsb2FkDQpwZXJfYXRobGV0ZV9jb3Jyc19hdmcgPC0gbG9hZF9hbmRfUlNJIHw+DQogIGdyb3VwX2J5KGFub25faWQpIHw+DQogIHN1bW1hcml6ZSgNCiAgICByID0gY29yKFJTSSwgYFRELTIuLkF2Zy4uQWNjZWwuTG9hZGAsIHVzZSA9ICJjb21wbGV0ZS5vYnMiKSwNCiAgICBuID0gbigpDQogICkgfD4NCiAgYXJyYW5nZShyKQ0KDQpnZ3Bsb3QocGVyX2F0aGxldGVfY29ycnNfYXZnLCBhZXMoeCA9IHJlb3JkZXIoYW5vbl9pZCwgciksIHkgPSByKSkgKw0KICBnZW9tX2NvbChmaWxsID0gIiNDRkI4N0MiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChyLCAyKSksIA0KICAgICAgICAgICAgICBoanVzdCA9IGlmZWxzZShwZXJfYXRobGV0ZV9jb3Jyc19hdmckciA+PSAwLCAtMC4xLCAxLjEpLA0KICAgICAgICAgICAgICBzaXplID0gMy4yLA0KICAgICAgICAgICAgICBjb2xvciA9ICIjMDAwMDAwIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHRpdGxlID0gIlBlciBBdGhsZXRlIENvcnJlbGF0aW9uIEJldHdlZW4gQXZnIDMtRGF5IEFjY2VsIExvYWQgYW5kIFJTSSIsDQogICAgICAgeCA9ICJBdGhsZXRlIiwNCiAgICAgICB5ID0gIkNvcnJlbGF0aW9uIChyKSIpICsNCiAgdGhlbWVfY2xhc3NpYygpDQoNCg0KIyBUb3RhbCAzIGRheSBhY2NlbCBsb2FkDQpwZXJfYXRobGV0ZV9jb3Jyc190b3RhbCA8LSBsb2FkX2FuZF9SU0kgfD4NCiAgZ3JvdXBfYnkoYW5vbl9pZCkgfD4NCiAgc3VtbWFyaXplKA0KICAgIHIgPSBjb3IoUlNJLCBgVEQtMi4uVG90YWwuLkFjY2VsLkxvYWRgLCB1c2UgPSAiY29tcGxldGUub2JzIiksDQogICAgbiA9IG4oKQ0KICApIHw+DQogIGFycmFuZ2UocikNCg0KZ2dwbG90KHBlcl9hdGhsZXRlX2NvcnJzX3RvdGFsLCBhZXMoeCA9IHJlb3JkZXIoYW5vbl9pZCwgciksIHkgPSByKSkgKw0KICBnZW9tX2NvbChmaWxsID0gIiNDRkI4N0MiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChyLCAyKSksIA0KICAgICAgICAgICAgICBoanVzdCA9IGlmZWxzZShwZXJfYXRobGV0ZV9jb3Jyc190b3RhbCRyID49IDAsIC0wLjEsIDEuMSksDQogICAgICAgICAgICAgIHNpemUgPSAzLjIsDQogICAgICAgICAgICAgIGNvbG9yID0gIiMwMDAwMDAiKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIGxhYnModGl0bGUgPSAiUGVyIEF0aGxldGUgQ29ycmVsYXRpb24gQmV0d2VlbiBUb3RhbCAzLURheSBBY2NlbCBMb2FkIGFuZCBSU0kiLA0KICAgICAgIHggPSAiQXRobGV0ZSIsDQogICAgICAgeSA9ICJDb3JyZWxhdGlvbiAocikiKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQoNCg0KIyBBdmVyYWdlIDIgZGF5IGFjY2VsIGxvYWQNCnBlcl9hdGhsZXRlX2NvcnJzX2F2ZyA8LSBsb2FkX2FuZF9SU0kgfD4NCiAgZ3JvdXBfYnkoYW5vbl9pZCkgfD4NCiAgc3VtbWFyaXplKA0KICAgIHIgPSBjb3IoUlNJLCBgVEQtMS4uQXZnLi5BY2NlbC5Mb2FkYCwgdXNlID0gImNvbXBsZXRlLm9icyIpLA0KICAgIG4gPSBuKCkNCiAgKSB8Pg0KICBhcnJhbmdlKHIpDQoNCmdncGxvdChwZXJfYXRobGV0ZV9jb3Jyc19hdmcsIGFlcyh4ID0gcmVvcmRlcihhbm9uX2lkLCByKSwgeSA9IHIpKSArDQogIGdlb21fY29sKGZpbGwgPSAiI0NGQjg3QyIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHIsIDIpKSwgDQogICAgICAgICAgICAgIGhqdXN0ID0gaWZlbHNlKHBlcl9hdGhsZXRlX2NvcnJzX2F2ZyRyID49IDAsIC0wLjEsIDEuMSksDQogICAgICAgICAgICAgIHNpemUgPSAzLjIsDQogICAgICAgICAgICAgIGNvbG9yID0gIiMwMDAwMDAiKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIGxhYnModGl0bGUgPSAiUGVyIEF0aGxldGUgQ29ycmVsYXRpb24gQmV0d2VlbiBBdmcgMi1EYXkgQWNjZWwgTG9hZCBhbmQgUlNJIiwNCiAgICAgICB4ID0gIkF0aGxldGUiLA0KICAgICAgIHkgPSAiQ29ycmVsYXRpb24gKHIpIikgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KDQojIFRvdGFsIDIgZGF5IGFjY2VsIGxvYWQNCnBlcl9hdGhsZXRlX2NvcnJzX3RvdGFsIDwtIGxvYWRfYW5kX1JTSSB8Pg0KICBncm91cF9ieShhbm9uX2lkKSB8Pg0KICBzdW1tYXJpemUoDQogICAgciA9IGNvcihSU0ksIGBURC0xLi5Ub3RhbC4uQWNjZWwuTG9hZGAsIHVzZSA9ICJjb21wbGV0ZS5vYnMiKSwNCiAgICBuID0gbigpDQogICkgfD4NCiAgYXJyYW5nZShyKQ0KDQpnZ3Bsb3QocGVyX2F0aGxldGVfY29ycnNfdG90YWwsIGFlcyh4ID0gcmVvcmRlcihhbm9uX2lkLCByKSwgeSA9IHIpKSArDQogIGdlb21fY29sKGZpbGwgPSAiI0NGQjg3QyIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHIsIDIpKSwgDQogICAgICAgICAgICAgIGhqdXN0ID0gaWZlbHNlKHBlcl9hdGhsZXRlX2NvcnJzX3RvdGFsJHIgPj0gMCwgLTAuMSwgMS4xKSwNCiAgICAgICAgICAgICAgc2l6ZSA9IDMuMiwNCiAgICAgICAgICAgICAgY29sb3IgPSAiIzAwMDAwMCIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicyh0aXRsZSA9ICJQZXIgQXRobGV0ZSBDb3JyZWxhdGlvbiBCZXR3ZWVuIFRvdGFsIDItRGF5IEFjY2VsIExvYWQgYW5kIFJTSSIsDQogICAgICAgeCA9ICJBdGhsZXRlIiwNCiAgICAgICB5ID0gIkNvcnJlbGF0aW9uIChyKSIpICsNCiAgdGhlbWVfY2xhc3NpYygpDQpgYGANCklEXzY0IHNlZW0gdG8gaGF2ZSBhIG1vZGVyYXRsZXkgc3Ryb25nIG5lZ2F0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gYWNjZWxlcmF0aW9uIGxvYWQgYW5kIFJTSS4NCg0KDQpgYGB7ciBQZXIgQXRobGV0ZSBKdW1wIExvYWQgQ29ycmVsYXRpb25zfQ0KIyBKVU1QIExPQUQNCiMgQXZlcmFnZSA3IGRheSBqdW1wIGxvYWQNCnBlcl9hdGhsZXRlX2NvcnJzX2F2ZyA8LSBsb2FkX2FuZF9SU0kgfD4NCiAgZ3JvdXBfYnkoYW5vbl9pZCkgfD4NCiAgc3VtbWFyaXplKA0KICAgIHIgPSBjb3IoUlNJLCBgVEQtNi4uQXZnLi5KdW1wLkxvYWRgLCB1c2UgPSAiY29tcGxldGUub2JzIiksDQogICAgbiA9IG4oKQ0KICApIHw+DQogIGFycmFuZ2UocikNCg0KZ2dwbG90KHBlcl9hdGhsZXRlX2NvcnJzX2F2ZywgYWVzKHggPSByZW9yZGVyKGFub25faWQsIHIpLCB5ID0gcikpICsNCiAgZ2VvbV9jb2woZmlsbCA9ICIjQ0ZCODdDIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQociwgMikpLCANCiAgICAgICAgICAgICAgaGp1c3QgPSBpZmVsc2UocGVyX2F0aGxldGVfY29ycnNfYXZnJHIgPj0gMCwgLTAuMSwgMS4xKSwNCiAgICAgICAgICAgICAgc2l6ZSA9IDMuMiwNCiAgICAgICAgICAgICAgY29sb3IgPSAiIzAwMDAwMCIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicyh0aXRsZSA9ICJQZXIgQXRobGV0ZSBDb3JyZWxhdGlvbiBCZXR3ZWVuIEF2ZyA3LURheSBKdW1wIExvYWQgYW5kIFJTSSIsDQogICAgICAgeCA9ICJBdGhsZXRlIiwNCiAgICAgICB5ID0gIkNvcnJlbGF0aW9uIChyKSIpICsNCiAgdGhlbWVfY2xhc3NpYygpDQoNCg0KIyBUb3RhbCA3IGRheSBqdW1wIGxvYWQNCnBlcl9hdGhsZXRlX2NvcnJzX3RvdGFsIDwtIGxvYWRfYW5kX1JTSSB8Pg0KICBncm91cF9ieShhbm9uX2lkKSB8Pg0KICBzdW1tYXJpemUoDQogICAgciA9IGNvcihSU0ksIGBURC02Li5Ub3RhbC4uSnVtcC5Mb2FkYCwgdXNlID0gImNvbXBsZXRlLm9icyIpLA0KICAgIG4gPSBuKCkNCiAgKSB8Pg0KICBhcnJhbmdlKHIpDQoNCmdncGxvdChwZXJfYXRobGV0ZV9jb3Jyc190b3RhbCwgYWVzKHggPSByZW9yZGVyKGFub25faWQsIHIpLCB5ID0gcikpICsNCiAgZ2VvbV9jb2woZmlsbCA9ICIjQ0ZCODdDIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQociwgMikpLCANCiAgICAgICAgICAgICAgaGp1c3QgPSBpZmVsc2UocGVyX2F0aGxldGVfY29ycnNfdG90YWwkciA+PSAwLCAtMC4xLCAxLjEpLA0KICAgICAgICAgICAgICBzaXplID0gMy4yLA0KICAgICAgICAgICAgICBjb2xvciA9ICIjMDAwMDAwIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHRpdGxlID0gIlBlciBBdGhsZXRlIENvcnJlbGF0aW9uIEJldHdlZW4gVG90YWwgNy1EYXkgSnVtcCBMb2FkIGFuZCBSU0kiLA0KICAgICAgIHggPSAiQXRobGV0ZSIsDQogICAgICAgeSA9ICJDb3JyZWxhdGlvbiAocikiKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQoNCg0KIyBBdmVyYWdlIDMgZGF5IGp1bXAgbG9hZA0KcGVyX2F0aGxldGVfY29ycnNfYXZnIDwtIGxvYWRfYW5kX1JTSSB8Pg0KICBncm91cF9ieShhbm9uX2lkKSB8Pg0KICBzdW1tYXJpemUoDQogICAgciA9IGNvcihSU0ksIGBURC0yLi5BdmcuLkp1bXAuTG9hZGAsIHVzZSA9ICJjb21wbGV0ZS5vYnMiKSwNCiAgICBuID0gbigpDQogICkgfD4NCiAgYXJyYW5nZShyKQ0KDQpnZ3Bsb3QocGVyX2F0aGxldGVfY29ycnNfYXZnLCBhZXMoeCA9IHJlb3JkZXIoYW5vbl9pZCwgciksIHkgPSByKSkgKw0KICBnZW9tX2NvbChmaWxsID0gIiNDRkI4N0MiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChyLCAyKSksIA0KICAgICAgICAgICAgICBoanVzdCA9IGlmZWxzZShwZXJfYXRobGV0ZV9jb3Jyc19hdmckciA+PSAwLCAtMC4xLCAxLjEpLA0KICAgICAgICAgICAgICBzaXplID0gMy4yLA0KICAgICAgICAgICAgICBjb2xvciA9ICIjMDAwMDAwIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHRpdGxlID0gIlBlciBBdGhsZXRlIENvcnJlbGF0aW9uIEJldHdlZW4gQXZnIDMtRGF5IEp1bXAgTG9hZCBhbmQgUlNJIiwNCiAgICAgICB4ID0gIkF0aGxldGUiLA0KICAgICAgIHkgPSAiQ29ycmVsYXRpb24gKHIpIikgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KDQojIFRvdGFsIDMgZGF5IGp1bXAgbG9hZA0KcGVyX2F0aGxldGVfY29ycnNfdG90YWwgPC0gbG9hZF9hbmRfUlNJIHw+DQogIGdyb3VwX2J5KGFub25faWQpIHw+DQogIHN1bW1hcml6ZSgNCiAgICByID0gY29yKFJTSSwgYFRELTIuLlRvdGFsLi5KdW1wLkxvYWRgLCB1c2UgPSAiY29tcGxldGUub2JzIiksDQogICAgbiA9IG4oKQ0KICApIHw+DQogIGFycmFuZ2UocikNCg0KZ2dwbG90KHBlcl9hdGhsZXRlX2NvcnJzX3RvdGFsLCBhZXMoeCA9IHJlb3JkZXIoYW5vbl9pZCwgciksIHkgPSByKSkgKw0KICBnZW9tX2NvbChmaWxsID0gIiNDRkI4N0MiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChyLCAyKSksIA0KICAgICAgICAgICAgICBoanVzdCA9IGlmZWxzZShwZXJfYXRobGV0ZV9jb3Jyc190b3RhbCRyID49IDAsIC0wLjEsIDEuMSksDQogICAgICAgICAgICAgIHNpemUgPSAzLjIsDQogICAgICAgICAgICAgIGNvbG9yID0gIiMwMDAwMDAiKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIGxhYnModGl0bGUgPSAiUGVyIEF0aGxldGUgQ29ycmVsYXRpb24gQmV0d2VlbiBUb3RhbCAzLURheSBKdW1wIExvYWQgYW5kIFJTSSIsDQogICAgICAgeCA9ICJBdGhsZXRlIiwNCiAgICAgICB5ID0gIkNvcnJlbGF0aW9uIChyKSIpICsNCiAgdGhlbWVfY2xhc3NpYygpDQoNCg0KDQojIEF2ZXJhZ2UgMiBkYXkganVtcCBsb2FkDQpwZXJfYXRobGV0ZV9jb3Jyc19hdmcgPC0gbG9hZF9hbmRfUlNJIHw+DQogIGdyb3VwX2J5KGFub25faWQpIHw+DQogIHN1bW1hcml6ZSgNCiAgICByID0gY29yKFJTSSwgYFRELTEuLkF2Zy4uSnVtcC5Mb2FkYCwgdXNlID0gImNvbXBsZXRlLm9icyIpLA0KICAgIG4gPSBuKCkNCiAgKSB8Pg0KICBhcnJhbmdlKHIpDQoNCmdncGxvdChwZXJfYXRobGV0ZV9jb3Jyc19hdmcsIGFlcyh4ID0gcmVvcmRlcihhbm9uX2lkLCByKSwgeSA9IHIpKSArDQogIGdlb21fY29sKGZpbGwgPSAiI0NGQjg3QyIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHIsIDIpKSwgDQogICAgICAgICAgICAgIGhqdXN0ID0gaWZlbHNlKHBlcl9hdGhsZXRlX2NvcnJzX2F2ZyRyID49IDAsIC0wLjEsIDEuMSksDQogICAgICAgICAgICAgIHNpemUgPSAzLjIsDQogICAgICAgICAgICAgIGNvbG9yID0gIiMwMDAwMDAiKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIGxhYnModGl0bGUgPSAiUGVyIEF0aGxldGUgQ29ycmVsYXRpb24gQmV0d2VlbiBBdmcgMi1EYXkgSnVtcCBMb2FkIGFuZCBSU0kiLA0KICAgICAgIHggPSAiQXRobGV0ZSIsDQogICAgICAgeSA9ICJDb3JyZWxhdGlvbiAocikiKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQoNCiMgVG90YWwgMiBkYXkganVtcCBsb2FkDQpwZXJfYXRobGV0ZV9jb3Jyc190b3RhbCA8LSBsb2FkX2FuZF9SU0kgfD4NCiAgZ3JvdXBfYnkoYW5vbl9pZCkgfD4NCiAgc3VtbWFyaXplKA0KICAgIHIgPSBjb3IoUlNJLCBgVEQtMS4uVG90YWwuLkp1bXAuTG9hZGAsIHVzZSA9ICJjb21wbGV0ZS5vYnMiKSwNCiAgICBuID0gbigpDQogICkgfD4NCiAgYXJyYW5nZShyKQ0KDQpnZ3Bsb3QocGVyX2F0aGxldGVfY29ycnNfdG90YWwsIGFlcyh4ID0gcmVvcmRlcihhbm9uX2lkLCByKSwgeSA9IHIpKSArDQogIGdlb21fY29sKGZpbGwgPSAiI0NGQjg3QyIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHIsIDIpKSwgDQogICAgICAgICAgICAgIGhqdXN0ID0gaWZlbHNlKHBlcl9hdGhsZXRlX2NvcnJzX3RvdGFsJHIgPj0gMCwgLTAuMSwgMS4xKSwNCiAgICAgICAgICAgICAgc2l6ZSA9IDMuMiwNCiAgICAgICAgICAgICAgY29sb3IgPSAiIzAwMDAwMCIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicyh0aXRsZSA9ICJQZXIgQXRobGV0ZSBDb3JyZWxhdGlvbiBCZXR3ZWVuIFRvdGFsIDItRGF5IEp1bXAgTG9hZCBhbmQgUlNJIiwNCiAgICAgICB4ID0gIkF0aGxldGUiLA0KICAgICAgIHkgPSAiQ29ycmVsYXRpb24gKHIpIikgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KIyBUaGlzIGFsbG93cyB1cyB0byBzZWUgd2hpY2ggYXRobGV0ZSdzIFJTSSBzY29yZXMgYXJlIG1vc3QgZWZmZWN0ZWQgYnkgdGhlIHByaW9yIHdlZWsncyBsb2FkDQpgYGANCg0KDQoNCg0KYGBge3J9DQoNCnNldC5zZWVkKDQyKQ0KDQojIENyZWF0ZSBncm91cGVkIDUtZm9sZCBDViBzcGxpdHMgYnkgYW5vbl9pZA0KY3Zfc3BsaXRzIDwtIGdyb3VwX3Zmb2xkX2N2KGxvYWRfYW5kX1JTSSwgZ3JvdXAgPSBhbm9uX2lkLCB2ID0gNSkNCg0KIyBNaXhlZCBFZmZlY3RzIE1vZGVsIHdpdGggc3RhbmRhcmRpemVkIHByZWRpY3RvcnMNCmN2X21peGVkIDwtIGZ1bmN0aW9uKHNwbGl0KSB7DQogIHRyYWluIDwtIHRyYWluaW5nKHNwbGl0KQ0KICB0ZXN0IDwtIHRlc3Rpbmcoc3BsaXQpDQoNCiAgIyBNYW51YWxseSBzdGFuZGFyZGl6ZSB1c2luZyB0cmFpbmluZyBzdGF0cw0KICBtZWFuX2FjY2VsIDwtIG1lYW4odHJhaW4kTGFzdC5XZWVrLi5BdmcuLkFjY2VsLkxvYWQsIG5hLnJtID0gVFJVRSkNCiAgc2RfYWNjZWwgICA8LSBzZCh0cmFpbiRMYXN0LldlZWsuLkF2Zy4uQWNjZWwuTG9hZCwgbmEucm0gPSBUUlVFKQ0KDQogIG1lYW5fanVtcCAgPC0gbWVhbih0cmFpbiRMYXN0LldlZWsuLkF2Zy4uSnVtcC5Mb2FkLCBuYS5ybSA9IFRSVUUpDQogIHNkX2p1bXAgICAgPC0gc2QodHJhaW4kTGFzdC5XZWVrLi5BdmcuLkp1bXAuTG9hZCwgbmEucm0gPSBUUlVFKQ0KDQogIHRyYWluIDwtIHRyYWluICU+JQ0KICAgIG11dGF0ZSgNCiAgICAgIHpfYXZnX2FjY2VsID0gKExhc3QuV2Vlay4uQXZnLi5BY2NlbC5Mb2FkIC0gbWVhbl9hY2NlbCkgLyBzZF9hY2NlbCwNCiAgICAgIHpfYXZnX2p1bXAgID0gKExhc3QuV2Vlay4uQXZnLi5KdW1wLkxvYWQgLSBtZWFuX2p1bXApIC8gc2RfanVtcA0KICAgICkNCg0KICB0ZXN0IDwtIHRlc3QgJT4lDQogICAgbXV0YXRlKA0KICAgICAgel9hdmdfYWNjZWwgPSAoTGFzdC5XZWVrLi5BdmcuLkFjY2VsLkxvYWQgLSBtZWFuX2FjY2VsKSAvIHNkX2FjY2VsLA0KICAgICAgel9hdmdfanVtcCAgPSAoTGFzdC5XZWVrLi5BdmcuLkp1bXAuTG9hZCAtIG1lYW5fanVtcCkgLyBzZF9qdW1wDQogICAgKQ0KDQogIG1vZGVsIDwtIGxtZXIoUlNJIH4gel9hdmdfYWNjZWwgKyB6X2F2Z19qdW1wICsgKDEgfCBhbm9uX2lkKSwgZGF0YSA9IHRyYWluKQ0KICBwcmVkcyA8LSBwcmVkaWN0KG1vZGVsLCBuZXdkYXRhID0gdGVzdCwgYWxsb3cubmV3LmxldmVscyA9IFRSVUUpDQoNCiAgcm1zZV92ZWModHJ1dGggPSB0ZXN0JFJTSSwgZXN0aW1hdGUgPSBwcmVkcykNCn0NCg0KIyBHQU0gTW9kZWwgd2l0aCBzdGFuZGFyZGl6ZWQgcHJlZGljdG9ycw0KY3ZfZ2FtIDwtIGZ1bmN0aW9uKHNwbGl0KSB7DQogIHRyYWluIDwtIHRyYWluaW5nKHNwbGl0KQ0KICB0ZXN0IDwtIHRlc3Rpbmcoc3BsaXQpDQoNCiAgIyBNYW51YWxseSBzdGFuZGFyZGl6ZSB1c2luZyB0cmFpbmluZyBzdGF0cw0KICBtZWFuX2FjY2VsIDwtIG1lYW4odHJhaW4kTGFzdC5XZWVrLi5BdmcuLkFjY2VsLkxvYWQsIG5hLnJtID0gVFJVRSkNCiAgc2RfYWNjZWwgICA8LSBzZCh0cmFpbiRMYXN0LldlZWsuLkF2Zy4uQWNjZWwuTG9hZCwgbmEucm0gPSBUUlVFKQ0KDQogIG1lYW5fanVtcCAgPC0gbWVhbih0cmFpbiRMYXN0LldlZWsuLkF2Zy4uSnVtcC5Mb2FkLCBuYS5ybSA9IFRSVUUpDQogIHNkX2p1bXAgICAgPC0gc2QodHJhaW4kTGFzdC5XZWVrLi5BdmcuLkp1bXAuTG9hZCwgbmEucm0gPSBUUlVFKQ0KDQogIHRyYWluIDwtIHRyYWluICU+JQ0KICAgIG11dGF0ZSgNCiAgICAgIHpfYXZnX2FjY2VsID0gKExhc3QuV2Vlay4uQXZnLi5BY2NlbC5Mb2FkIC0gbWVhbl9hY2NlbCkgLyBzZF9hY2NlbCwNCiAgICAgIHpfYXZnX2p1bXAgID0gKExhc3QuV2Vlay4uQXZnLi5KdW1wLkxvYWQgLSBtZWFuX2p1bXApIC8gc2RfanVtcA0KICAgICkNCg0KICB0ZXN0IDwtIHRlc3QgJT4lDQogICAgbXV0YXRlKA0KICAgICAgel9hdmdfYWNjZWwgPSAoTGFzdC5XZWVrLi5BdmcuLkFjY2VsLkxvYWQgLSBtZWFuX2FjY2VsKSAvIHNkX2FjY2VsLA0KICAgICAgel9hdmdfanVtcCAgPSAoTGFzdC5XZWVrLi5BdmcuLkp1bXAuTG9hZCAtIG1lYW5fanVtcCkgLyBzZF9qdW1wDQogICAgKQ0KDQogIG1vZGVsIDwtIGdhbShSU0kgfiBzKHpfYXZnX2FjY2VsKSArIHMoel9hdmdfanVtcCksIGRhdGEgPSB0cmFpbikNCiAgcHJlZHMgPC0gcHJlZGljdChtb2RlbCwgbmV3ZGF0YSA9IHRlc3QpDQoNCiAgcm1zZV92ZWModHJ1dGggPSB0ZXN0JFJTSSwgZXN0aW1hdGUgPSBwcmVkcykNCn0NCg0KIyBSdW4gQ1YgZm9yIGJvdGggbW9kZWxzDQptaXhlZF9ybXNlcyA8LSBtYXBfZGJsKGN2X3NwbGl0cyRzcGxpdHMsIGN2X21peGVkKQ0KZ2FtX3Jtc2VzICAgPC0gbWFwX2RibChjdl9zcGxpdHMkc3BsaXRzLCBjdl9nYW0pDQoNCiMgU3VtbWFyeSB0YWJsZSBvZiBtZWFuIFJNU0VzDQp0aWJibGUoDQogIE1vZGVsID0gYygiTWl4ZWQgRWZmZWN0cyAoc3RhbmRhcmRpemVkKSIsICJHQU0gKHN0YW5kYXJkaXplZCkiKSwNCiAgTWVhbl9STVNFID0gYyhtZWFuKG1peGVkX3Jtc2VzLCBuYS5ybSA9IFRSVUUpLCBtZWFuKGdhbV9ybXNlcywgbmEucm0gPSBUUlVFKSkNCikNCg0KYGBgDQoNCmBgYHtyfQ0KIyBGaXQgZml4ZWQgZWZmZWN0cyBtb2RlbCBvbiBmdWxsIGRhdGENCmF2Z19maXhlZF9tb2RlbCA8LSBsbShSU0kgfiBMYXN0LldlZWsuLkF2Zy4uQWNjZWwuTG9hZCArIExhc3QuV2Vlay4uQXZnLi5KdW1wLkxvYWQgKyBmYWN0b3IoYW5vbl9pZCksDQogICAgICAgICAgICAgICAgICBkYXRhID0gbG9hZF9hbmRfUlNJKQ0KDQojIFZpZXcgc3VtbWFyeQ0Kc3VtbWFyeShhdmdfZml4ZWRfbW9kZWwpDQoNCmBgYA0KDQpgYGB7ciB0b3RhbCBtb2RlbHN9DQpzZXQuc2VlZCg0MikNCg0KIyBDcmVhdGUgZ3JvdXBlZCA1LWZvbGQgQ1Ygc3BsaXRzIGJ5IGFub25faWQNCmN2X3NwbGl0cyA8LSBncm91cF92Zm9sZF9jdihsb2FkX2FuZF9SU0ksIGdyb3VwID0gYW5vbl9pZCwgdiA9IDUpDQoNCiMgTWl4ZWQgRWZmZWN0cyBNb2RlbCB3aXRoIHN0YW5kYXJkaXplZCB0b3RhbCBsb2FkIHByZWRpY3RvcnMNCmN2X21peGVkX3RvdGFsIDwtIGZ1bmN0aW9uKHNwbGl0KSB7DQogIHRyYWluIDwtIHRyYWluaW5nKHNwbGl0KQ0KICB0ZXN0IDwtIHRlc3Rpbmcoc3BsaXQpDQoNCiAgIyBNYW51YWxseSBzdGFuZGFyZGl6ZSB1c2luZyB0cmFpbmluZyBzdGF0cw0KICBtZWFuX2FjY2VsIDwtIG1lYW4odHJhaW4kTGFzdC5XZWVrLi5Ub3RhbC4uQWNjZWwuTG9hZCwgbmEucm0gPSBUUlVFKQ0KICBzZF9hY2NlbCAgIDwtIHNkKHRyYWluJExhc3QuV2Vlay4uVG90YWwuLkFjY2VsLkxvYWQsIG5hLnJtID0gVFJVRSkNCg0KICBtZWFuX2p1bXAgIDwtIG1lYW4odHJhaW4kTGFzdC5XZWVrLi5Ub3RhbC4uSnVtcC5Mb2FkLCBuYS5ybSA9IFRSVUUpDQogIHNkX2p1bXAgICAgPC0gc2QodHJhaW4kTGFzdC5XZWVrLi5Ub3RhbC4uSnVtcC5Mb2FkLCBuYS5ybSA9IFRSVUUpDQoNCiAgdHJhaW4gPC0gdHJhaW4gJT4lDQogICAgbXV0YXRlKA0KICAgICAgel90b3RhbF9hY2NlbCA9IChMYXN0LldlZWsuLlRvdGFsLi5BY2NlbC5Mb2FkIC0gbWVhbl9hY2NlbCkgLyBzZF9hY2NlbCwNCiAgICAgIHpfdG90YWxfanVtcCAgPSAoTGFzdC5XZWVrLi5Ub3RhbC4uSnVtcC5Mb2FkIC0gbWVhbl9qdW1wKSAvIHNkX2p1bXANCiAgICApDQoNCiAgdGVzdCA8LSB0ZXN0ICU+JQ0KICAgIG11dGF0ZSgNCiAgICAgIHpfdG90YWxfYWNjZWwgPSAoTGFzdC5XZWVrLi5Ub3RhbC4uQWNjZWwuTG9hZCAtIG1lYW5fYWNjZWwpIC8gc2RfYWNjZWwsDQogICAgICB6X3RvdGFsX2p1bXAgID0gKExhc3QuV2Vlay4uVG90YWwuLkp1bXAuTG9hZCAtIG1lYW5fanVtcCkgLyBzZF9qdW1wDQogICAgKQ0KDQogIG1vZGVsIDwtIGxtZXIoUlNJIH4gel90b3RhbF9hY2NlbCArIHpfdG90YWxfanVtcCArICgxIHwgYW5vbl9pZCksIGRhdGEgPSB0cmFpbikNCiAgcHJlZHMgPC0gcHJlZGljdChtb2RlbCwgbmV3ZGF0YSA9IHRlc3QsIGFsbG93Lm5ldy5sZXZlbHMgPSBUUlVFKQ0KDQogIHJtc2VfdmVjKHRydXRoID0gdGVzdCRSU0ksIGVzdGltYXRlID0gcHJlZHMpDQp9DQoNCiMgR0FNIE1vZGVsIHdpdGggc3RhbmRhcmRpemVkIHRvdGFsIGxvYWQgcHJlZGljdG9ycw0KY3ZfZ2FtX3RvdGFsIDwtIGZ1bmN0aW9uKHNwbGl0KSB7DQogIHRyYWluIDwtIHRyYWluaW5nKHNwbGl0KQ0KICB0ZXN0IDwtIHRlc3Rpbmcoc3BsaXQpDQoNCiAgIyBNYW51YWxseSBzdGFuZGFyZGl6ZSB1c2luZyB0cmFpbmluZyBzdGF0cw0KICBtZWFuX2FjY2VsIDwtIG1lYW4odHJhaW4kTGFzdC5XZWVrLi5Ub3RhbC4uQWNjZWwuTG9hZCwgbmEucm0gPSBUUlVFKQ0KICBzZF9hY2NlbCAgIDwtIHNkKHRyYWluJExhc3QuV2Vlay4uVG90YWwuLkFjY2VsLkxvYWQsIG5hLnJtID0gVFJVRSkNCg0KICBtZWFuX2p1bXAgIDwtIG1lYW4odHJhaW4kTGFzdC5XZWVrLi5Ub3RhbC4uSnVtcC5Mb2FkLCBuYS5ybSA9IFRSVUUpDQogIHNkX2p1bXAgICAgPC0gc2QodHJhaW4kTGFzdC5XZWVrLi5Ub3RhbC4uSnVtcC5Mb2FkLCBuYS5ybSA9IFRSVUUpDQoNCiAgdHJhaW4gPC0gdHJhaW4gJT4lDQogICAgbXV0YXRlKA0KICAgICAgel90b3RhbF9hY2NlbCA9IChMYXN0LldlZWsuLlRvdGFsLi5BY2NlbC5Mb2FkIC0gbWVhbl9hY2NlbCkgLyBzZF9hY2NlbCwNCiAgICAgIHpfdG90YWxfanVtcCAgPSAoTGFzdC5XZWVrLi5Ub3RhbC4uSnVtcC5Mb2FkIC0gbWVhbl9qdW1wKSAvIHNkX2p1bXANCiAgICApDQoNCiAgdGVzdCA8LSB0ZXN0ICU+JQ0KICAgIG11dGF0ZSgNCiAgICAgIHpfdG90YWxfYWNjZWwgPSAoTGFzdC5XZWVrLi5Ub3RhbC4uQWNjZWwuTG9hZCAtIG1lYW5fYWNjZWwpIC8gc2RfYWNjZWwsDQogICAgICB6X3RvdGFsX2p1bXAgID0gKExhc3QuV2Vlay4uVG90YWwuLkp1bXAuTG9hZCAtIG1lYW5fanVtcCkgLyBzZF9qdW1wDQogICAgKQ0KDQogIG1vZGVsIDwtIGdhbShSU0kgfiBzKHpfdG90YWxfYWNjZWwpICsgcyh6X3RvdGFsX2p1bXApLCBkYXRhID0gdHJhaW4pDQogIHByZWRzIDwtIHByZWRpY3QobW9kZWwsIG5ld2RhdGEgPSB0ZXN0KQ0KDQogIHJtc2VfdmVjKHRydXRoID0gdGVzdCRSU0ksIGVzdGltYXRlID0gcHJlZHMpDQp9DQoNCiMgUnVuIENWIGZvciBib3RoIG1vZGVscyB3aXRoIHRvdGFsIGxvYWRzDQptaXhlZF9ybXNlc190b3RhbCA8LSBtYXBfZGJsKGN2X3NwbGl0cyRzcGxpdHMsIGN2X21peGVkX3RvdGFsKQ0KZ2FtX3Jtc2VzX3RvdGFsICAgPC0gbWFwX2RibChjdl9zcGxpdHMkc3BsaXRzLCBjdl9nYW1fdG90YWwpDQoNCiMgU3VtbWFyeSB0YWJsZSBvZiBtZWFuIFJNU0VzDQp0aWJibGUoDQogIE1vZGVsID0gYygiTWl4ZWQgRWZmZWN0cyAoc3RhbmRhcmRpemVkIHRvdGFsIGxvYWQpIiwgIkdBTSAoc3RhbmRhcmRpemVkIHRvdGFsIGxvYWQpIiksDQogIE1lYW5fUk1TRSA9IGMobWVhbihtaXhlZF9ybXNlc190b3RhbCwgbmEucm0gPSBUUlVFKSwgbWVhbihnYW1fcm1zZXNfdG90YWwsIG5hLnJtID0gVFJVRSkpDQopDQoNCiMgRml0IGZpeGVkIGVmZmVjdHMgbW9kZWwgb24gZnVsbCBkYXRhIHdpdGggdG90YWwgbG9hZCBwcmVkaWN0b3JzDQpmaXhlZF9tb2RlbF90b3RhbCA8LSBsbShSU0kgfiBMYXN0LldlZWsuLlRvdGFsLi5BY2NlbC5Mb2FkICsgTGFzdC5XZWVrLi5Ub3RhbC4uSnVtcC5Mb2FkICsgZmFjdG9yKGFub25faWQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGxvYWRfYW5kX1JTSSkNCg0Kc3VtbWFyeShmaXhlZF9tb2RlbF90b3RhbCkNCg0KDQoNCmBgYA0KDQoNCiMjIyBRdWVzdGlvbiA0DQoNCiMjIyMgV2hhdCBpcyBlYWNoIGF0aGxldGUncyB2YXJpYXRpb24gaW4gUlNJPyBXaGF0IGlzIGEgbWVhbmluZ2Z1bCBjaGFuZ2UgaW4gUlNJIGZvciB0aGUgdGVhbSBhbmQgZm9yIGluZGl2aWR1YWwgYXRobGV0ZXM/DQoNCmBgYHtyfQ0KIyBTb21lIGJhc2ljIHZpc3VhbGl6YXRpb25zDQoNClZBTERfRm9yY2VEZWNrc19jbGVhbiA8LSBWQUxEX0ZvcmNlRGVja3NfY2xlYW4gJT4lDQogIGZpbHRlcihEYXRlID49IGFzLkRhdGUoIjIwMjQtMDktMjAiLCAnJVktJW0tJWQnKSkgJT4lDQogIGZpbHRlcighKGFub25faWQgJWluJSBjKCJJRF8xMCIsICJJRF8xNCIsICJJRF8xNSIsICJJRF8xOCIsICJJRF81NCIsICJJRF82NCIpKSkNCiAgDQojIEJveHBsb3Qgc2hvd2luZyBSU0kgZGlzdHJpYnV0aW9uIGZvciBlYWNoIGF0aGxldGUNCmdncGxvdChWQUxEX0ZvcmNlRGVja3NfY2xlYW4sIGFlcyhhbm9uX2lkLCBSU0kuLm0ucGVyLnMuKSkgKw0KICBnZW9tX2JveHBsb3QoY29sb3IgPSAiI0NGQjg3QyIpICsNCiAgbGFicyh0aXRsZSA9ICJSU0kgVmFyaWFiaWxpdHkgYnkgQXRobGV0ZSIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KDQojIExpbmUgYW5kIHNjYXR0ZXIgcGxvdCBzaG93aW5nIFJTSSB0cmVuZHMgb3ZlciB0aW1lIGZvciBlYWNoIGF0aGxldGUNCiMgSW5jbHVkZXMgYSBibGFjayBsaW5lIGZvciB0aGUgdGVhbSBhdmVyYWdlIFJTSSB0byBjb21wYXJlIGluZGl2aWR1YWwgcGVyZm9ybWFuY2UgdG8NCmdncGxvdChWQUxEX0ZvcmNlRGVja3NfY2xlYW4sIGFlcyhEYXRlLCBQbGF5ZXIuQXZlcmFnZS5SU0kuLm0ucGVyLnMuLCBjb2xvciA9IGFub25faWQpKSArDQogIGdlb21fcG9pbnQoKSArIA0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1GQUxTRSkgKw0KICBsYWJzKHRpdGxlID0gIlBsYXllciBSU0kgT3ZlciBUaW1lIHdpdGggVGVhbSBBdmVyYWdlIExpbmUiKSArDQogIGdlb21fbGluZShhZXMoeSA9IFRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSwgDQogICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgdGhlbWVfY2xhc3NpYygpDQoNCg0KIyBTbW9vdGhlZCBSU0kgVHJlbmQgb3ZlciB0aW1lDQpnZ3Bsb3QobG9hZF9hbmRfUlNJLCBhZXMoeCA9IFJTSV9EYXRlLCB5ID0gUlNJKSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBjb2xvciA9ICIjQ0ZCODdDIiwgZmlsbCA9ICIjQTJBNEEzIikgKw0KICBsYWJzKHRpdGxlID0gIlNtb290aGVkIFJTSSBUcmVuZCIsDQogICAgICAgeCA9ICJEYXRlIiwNCiAgICAgICB5ID0gIlJTSSBWYWx1ZSIpICsNCiAgdGhlbWVfY2xhc3NpYygpDQoNCg0KYGBgDQoNCg0KYGBge3J9DQprZW5kYWxsX2NvciA9IGNvcihWQUxEX0ZvcmNlRGVja3NfY2xlYW4kWCwgVkFMRF9Gb3JjZURlY2tzX2NsZWFuJFRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuLCBtZXRob2QgPSAia2VuZGFsbCIpKi0xDQpnZ3Bsb3QoZGF0YT1WQUxEX0ZvcmNlRGVja3NfY2xlYW4sIGFlcyh4PURhdGUsIHk9UGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLikpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpICsNCiAgbGFicyh0aXRsZT1rZW5kYWxsX2NvcikNCmBgYA0KDQpgYGB7cn0NCiN0YWtpbmcgb3V0IGFsbCBvZiB0aGUgSURzIGluIHRoZSBkYXRhIHNldA0KSURzIDwtIHVuaXF1ZShWQUxEX0ZvcmNlRGVja3NfY2xlYW4kYW5vbl9pZCkNCg0KI2ZvciBhbGwgdW5pcXVlIElEcywgY2FsY3VsYXRlIEtlbmRhbGwgcmFuayBjb3JyZWxhdGlvbiwgcGxvdCBwbGF5ZXIgUlNJIHRocm91Z2hvdXQgc2Vhc29uIA0KZm9yKGkgaW4gMToxMSl7DQogIFJTSSA8LSB1bmlxdWUoVkFMRF9Gb3JjZURlY2tzX2NsZWFuW1ZBTERfRm9yY2VEZWNrc19jbGVhbiRhbm9uX2lkID09IElEc1tpXSxdJFBsYXllci5BdmVyYWdlLlJTSS4ubS5wZXIucy4pDQogIGtlbmRhbGxfY29yIDwtIGNvcigxOmxlbmd0aChSU0kpLCBSU0ksIG1ldGhvZD0ia2VuZGFsbCIpKi0xICNjYWxjdWxhdGluZyBLZW5kYWxsIGNvcnJlbGF0aW9uDQoNCiNwbG90dGluZyBlYWNoIHBsYXllcidzIFJTSSB0aHJvdWdob3V0IHRoZSBzZWFzb24gd2l0aCB0aGVpciBjb3JyZWxhdGlvbiBhbmQgcm91Z2ggbW9kZWwgb2YgdGhlIHRyZW5kDQogIHAgPC0gZ2dwbG90KGRhdGEgPSBWQUxEX0ZvcmNlRGVja3NfY2xlYW5bVkFMRF9Gb3JjZURlY2tzX2NsZWFuJGFub25faWQgPT0gSURzW2ldLF0sIGFlcyh4PURhdGUsIHk9UGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLikpICsgDQogICAgZ2VvbV9wb2ludCgpICsNCiAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKw0KICAgIGxhYnModGl0bGUgPSBrZW5kYWxsX2Nvciwgc3VidGl0bGUgPSBJRHNbaV0pDQogIA0KI3ByaW5nIG91dCBlYWNoIHBsb3QNCiAgcHJpbnQocCkNCn0NCmBgYA0KDQoNCmBgYHtyIHBsb3R0aW5nIGVhY2ggcGxheWVyIFJTSSB2YWx1ZXMgYW5kIGNhbGN1bGF0ZWQgbWV0cmljcyBmb3IgdGhlIHNlYXNvbn0NCiNmb3IgYWxsIHRoZSBwbGF5ZXJzLCBjYWxjdWxhdGUgbWVhbiBhbmQgdmFyaWFuY2Ugb2YgdGhlaXIgUlNJIG1lYXN1cmVtZW50cyBhbmQgcGxvdA0KZm9yKGkgaW4gMToxMSl7DQogICNmb3IgZXZlcnkgcGxheWVyIGNhbGN1bGF0ZSBtZWFuIGFuZCB2YXJpYW5jZSB1c2luZyB0aW1lIHNlcmllcyBhc3N1bXB0aW9ucyBhbmQgZnVuY3Rpb25zIGZyb20gdGhlIHRpbWUgc2VyaWVzIGZ1bmN0aW9ucyBmaWxlDQogIG12IDwtIHNhbXBsZV9tZWFuX2FuZF92YXJpYW5jZSh1bmlxdWUoVkFMRF9Gb3JjZURlY2tzX2NsZWFuW1ZBTERfRm9yY2VEZWNrc19jbGVhbiRhbm9uX2lkID09IElEc1tpXSxdJFBsYXllci5BdmVyYWdlLlJTSS4ubS5wZXIucy4pKQ0KICANCiAgI3Bsb3R0aW5nIFJTSSBtZWFzdXJlbWVudHMgYWxvbmcgd2l0aCBjYWxjdWxhdGVkIG1lYW4gYW5kIDEgc3RhbmRhcmQgZGV2aWF0aW9uIGFib3ZlIGFuZCBiZWxvdyBtZWFuIGZvciBlYWNoIHBsYXllciBhbG9uZyB3aXRoIHRoZWlyIG1lYXN1cmVkIFJTSXMgdGhyb3VnaG91dCB0aGUgc2Vhc29uDQogIHAgPC0gZ2dwbG90KGRhdGEgPSBWQUxEX0ZvcmNlRGVja3NfY2xlYW5bVkFMRF9Gb3JjZURlY2tzX2NsZWFuJGFub25faWQgPT0gSURzW2ldLF0sIGFlcyh4PURhdGUsIHk9UGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLikpICsgDQogICAgZ2VvbV9wb2ludCgpICsNCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBtdltbMV1dKSArDQogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbXZbWzFdXSArIHNxcnQobXZbWzJdXSksIGNvbG9yPSIjQ0ZCODdDIikgKw0KICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG12W1sxXV0gLSBzcXJ0KG12W1syXV0pLCBjb2xvcj0iI0NGQjg3QyIpICsNCiAgICBsYWJzKHRpdGxlID0gIlJTSSBNZWFzdXJlbWVudHMgVGhyb3VnaG91dCBTZWFzb24gd2l0aCBNZWFuIGFuZCAxIFN0YW5kYXJkIERldmlhdGlvbiIsc3VidGl0bGUgPSBJRHNbaV0pDQogIA0KICAjcHJpbnRpbmcgb3V0IGVhY2ggcGxvdA0KICBwcmludChwKQ0KfQ0KYGBgDQoNCmBgYHtyIG1ha2luZyBjb2x1bW5zIHRvIGluZGF0ZSB3aGV0aGVyIGEgbWVhc3VyZW1lbnQgaXMgYWJvdmUgb3IgYmVsb3cgcGxheWVyIG1ldHJpY3N9DQojbWFraW5nIGVtcHR5IGNvbHVtbnMgdG8gYmUgZmlsbGVkIHdpdGggaW5kaWNhdG9yIHZhcmlhYmxlcw0KVkFMRF9Gb3JjZURlY2tzX2NsZWFuJFBsYXllci5BYm92ZS4xLlNEIDwtIHJlcChOQSw1NjUpDQpWQUxEX0ZvcmNlRGVja3NfY2xlYW4kUGxheWVyLkJlbG93LjEuU0QgPC0gcmVwKE5BLDU2NSkNClZBTERfRm9yY2VEZWNrc19jbGVhbiRQbGF5ZXIuQWJvdmUuMi5TRCA8LSByZXAoTkEsNTY1KQ0KVkFMRF9Gb3JjZURlY2tzX2NsZWFuJFBsYXllci5CZWxvdy4yLlNEIDwtIHJlcChOQSw1NjUpDQoNCiNmb3IgZXZlcnkgYXRobGV0ZSwgY2hlY2tpbmcgaWYgYSBzcGVjaWZpYyBSU0kgbWVhc3VyZW1lbnQgaXMgb3V0c2lkZSAxIHN0YW5kYXJkIGRldmlhdGlvbiBvciAyIGNhbGN1bGF0ZWQgZm9yIGVhY2ggYXRobGV0ZSBpbmRpdmlkdWFsbHkuIA0KZm9yKGkgaW4gMToxNil7DQogICNjYWxjdWxhdGluZyBlYWNoIHBsYXllcidzIG1lYW4gYW5kIHZhcmlhbmNlIHdpdGggdGltZSBzZXJpZXMgZnVuY3Rpb24gb24gdGhlIHRpbWUgc2VyaWVzIGZ1bmN0aW9ucyBmaWxlDQogIG12IDwtIHNhbXBsZV9tZWFuX2FuZF92YXJpYW5jZSh1bmlxdWUoVkFMRF9Gb3JjZURlY2tzX2NsZWFuW1ZBTERfRm9yY2VEZWNrc19jbGVhbiRhbm9uX2lkID09IElEc1tpXSxdJFBsYXllci5BdmVyYWdlLlJTSS4ubS5wZXIucy4pKQ0KICANCiAgI2NhbGN1bGF0aW5nIHRocmVzaG9sZHMgZm9yIDEgYW5kIDIgc3RhbmRhcmQgZGV2aWF0aW9ucyBhd2F5IGZyb20gbWVhbiBmb3IgZWFjaCBwbGF5ZXINCiAgc2R1MSA8LSBtdltbMV1dICsgc3FydChtdltbMl1dKQ0KICBzZGwxIDwtIG12W1sxXV0gLSBzcXJ0KG12W1syXV0pDQogIHNkdTIgPC0gbXZbWzFdXSArICgyKnNxcnQobXZbWzJdXSkpDQogIHNkbDIgPC0gbXZbWzFdXSAtICgyKnNxcnQobXZbWzJdXSkpDQogIA0KI2NoZWNraW5nIGlmIFJTSSB2YWx1ZSBpcyBiZWxvdyAxIHN0YW5kYXJkIGRldmlhdGlvbiBmb3IgZWFjaCBwbGF5ZXINCiAgVkFMRF9Gb3JjZURlY2tzX2NsZWFuW1ZBTERfRm9yY2VEZWNrc19jbGVhbiRhbm9uX2lkID09IElEc1tpXSxdJFBsYXllci5CZWxvdy4xLlNEIDwtIGlmZWxzZSgoVkFMRF9Gb3JjZURlY2tzX2NsZWFuW1ZBTERfRm9yY2VEZWNrc19jbGVhbiRhbm9uX2lkID09IElEc1tpXSxdJFBsYXllci5BdmVyYWdlLlJTSS4ubS5wZXIucy48c2RsMSksIDEsIDApDQogIA0KI2NoZWNraW5nIGlmIFJTSSB2YWx1ZSBpcyBhYm92ZSAxIHN0YW5kYXJkIGRldmlhdGlvbiBmb3IgZWFjaCBwbGF5ZXINCiAgVkFMRF9Gb3JjZURlY2tzX2NsZWFuW1ZBTERfRm9yY2VEZWNrc19jbGVhbiRhbm9uX2lkID09IElEc1tpXSxdJFBsYXllci5BYm92ZS4xLlNEIDwtIGlmZWxzZSgoVkFMRF9Gb3JjZURlY2tzX2NsZWFuW1ZBTERfRm9yY2VEZWNrc19jbGVhbiRhbm9uX2lkID09IElEc1tpXSxdJFBsYXllci5BdmVyYWdlLlJTSS4ubS5wZXIucy4+c2R1MSksIDEsIDApDQogIA0KI2NoZWNraW5nIGlmIFJTSSB2YWx1ZSBpcyBiZWxvdyAyIHN0YW5kYXJkIGRldmlhdGlvbnMgZm9yIGVhY2ggcGxheWVyDQogIFZBTERfRm9yY2VEZWNrc19jbGVhbltWQUxEX0ZvcmNlRGVja3NfY2xlYW4kYW5vbl9pZCA9PSBJRHNbaV0sXSRQbGF5ZXIuQmVsb3cuMi5TRCA8LSBpZmVsc2UoKFZBTERfRm9yY2VEZWNrc19jbGVhbltWQUxEX0ZvcmNlRGVja3NfY2xlYW4kYW5vbl9pZCA9PSBJRHNbaV0sXSRQbGF5ZXIuQXZlcmFnZS5SU0kuLm0ucGVyLnMuPHNkbDIpLCAxLCAwKQ0KICANCiNjaGVja2luZyBpZiBSU0kgdmFsdWUgaXMgYWJvdmUgMiBzdGFuZGFyZCBkZXZpYXRpb25zIGZvciBlYWNoIHBsYXllcg0KICBWQUxEX0ZvcmNlRGVja3NfY2xlYW5bVkFMRF9Gb3JjZURlY2tzX2NsZWFuJGFub25faWQgPT0gSURzW2ldLF0kUGxheWVyLkFib3ZlLjIuU0QgPC0gaWZlbHNlKChWQUxEX0ZvcmNlRGVja3NfY2xlYW5bVkFMRF9Gb3JjZURlY2tzX2NsZWFuJGFub25faWQgPT0gSURzW2ldLF0kUGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLj5zZHUyKSwgMSwgMCkNCn0NCg0KYGBgDQoNCmBgYHtyfQ0KI21ha2luZyBhIHBsb3QgdG8gc2hvdyBwb3RlbnRpYWxseSBzaWduaWZpY2FudCBSU0kgbWVhc3VyZW1lbnRzIHRocm91Z2hvdXQgdGhlIHNlYXNvbg0KI2RhcmsgZ3JlZW4gbWVhbnMgcG9pbnQgaXMgYWJvdmUgMSBzdGFuZGFyZCBkZXZpYXRpb24gZnJvbSBtZWFuDQojbGlnaHQgZ3JlZW4gbWVhbnMgcG9pbnQgaXMgYWJvdmUgMiBzdGFuZGFyZCBkZXZpYXRpb25zIGZyb20gbWVhbg0KI2RhcmsgcmVkIG1lYW5zIHBvaW50IGlzIGJlbG93IDEgc3RhbmRhcmQgZGV2aWF0aW9uIGZyb20gbWVhbg0KI2xpZ2h0IHJlZCBtZWFucyBwb2ludCBpcyBiZWxvdyAyIHN0YW5kYXJkIGRldmlhdGlvbnMgZnJvbSBtZWFuDQpnZ3Bsb3QoZGF0YT1WQUxEX0ZvcmNlRGVja3NfY2xlYW4sIGFlcyh4PURhdGUsIFBsYXllci5BdmVyYWdlLlJTSS4ubS5wZXIucy4pKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSBpZmVsc2UoVkFMRF9Gb3JjZURlY2tzX2NsZWFuJFBsYXllci5BYm92ZS4yLlNEID09IDEsICJwYWxlZ3JlZW4iLCBpZmVsc2UoVkFMRF9Gb3JjZURlY2tzX2NsZWFuJFBsYXllci5CZWxvdy4yLlNEID09IDEsICJyZWQiLCBpZmVsc2UoVkFMRF9Gb3JjZURlY2tzX2NsZWFuJFBsYXllci5CZWxvdy4xLlNEID09IDEsICJyZWQ0IiwgaWZlbHNlKFZBTERfRm9yY2VEZWNrc19jbGVhbiRQbGF5ZXIuQWJvdmUuMS5TRCA9PSAxLCAicGFsZWdyZWVuNCIsICJncmV5ODAiKSkpKSwgYWxwaGEgPSAwLjQpICsNCiAgbGFicyh0aXRsZSA9ICJTaWduaWZpY2FudCBSU0kgTWVhc3VyZW1lbnRzIFRocm91Z2hvdXQgdGhlIFNlYXNvbiIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANClRoaXMgcGxvdCBzaG93cyBlYWNoIHBsYXllcidzIG1lYXN1cmVkIFJTSSB0aHJvdWdob3V0IHRoZSBzZWFzb24uIFBvaW50cyB0aGF0IGFyZSBjb2xvcmVkIGdyYXkgYXJlIHBvaW50cyB3aGVyZSB0aGUgcGxheWVyIGRpZCBub3QgaGF2ZSBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gdGhlaXIgUlNJIGZyb20gdGhlaXIgbWVhbiBSU0kgdGhyb3VnaG91dCB0aGUgc2Vhc29uLiBEYXJrIGdyZWVuIGRvdHMgc2hvdyBSU0kgbWVhc3VyZW1lbnRzIHRoYXQgYXJlIGFib3ZlIDEgc3RhbmRhcmQgZGV2aWF0aW9uIGZvciBlYWNoIHBsYXllciBhbmQgbGlnaHQgZ3JlZW4gZG90cyBhcmUgUlNJIG1lYXN1cmVtZW50cyB0aGF0IGFyZSBhYm92ZSAyIHN0YW5kYXJkIGRldmlhdGlvbnMgZm9yIGVhY2ggcGxheWVyLiBBbG9uZyB0aGUgc2FtZSBsaW5lcywgZGFyayByZWQgZG90cyBzaG93biBwb2ludHMgaW4gd2hpY2ggdGhlIHBsYXllciBoYWQgYW4gUlNJIGJlbG93IDEgc3RhbmRhcmQgZGV2aWF0aW9uIGZyb20gdGhlaXIgUlNJIGRpc3RyaWJ1dGlvbiBhbmQgbGlnaHQgcmVkIGRvdHMgc2hvdyBwb2ludHMgaW4gd2hpY2ggdGhlIHBsYXllcidzIG1lYXN1cmVkIFJTSSBpcyBiZWxvdyAyIHN0YW5kYXJkIGRldmlhdGlvbnMgb2YgdGhlaXIgUlNJIGRpc3RyaWJ1dGlvbi4gDQpPbmUgaW50ZXJlc3RpbmcgdGhpbmcgYWJvdXQgdGhpcyBwbG90IGlzIHRoYXQgdGhlcmUgYXJlIG5vIG1lYXN1cmVtZW50cyB0aGF0IGFyZSBiZWxvdyBldmVuIDEgc3RhbmRhcmQgZGV2aWF0aW9uIGZvciBhbnkgcGxheWVyIGFmdGVyIEZlYnJ1YXJ5IHN0YXJ0cy4gSWYgYW55dGhpbmcsIHRoZXJlIHNlZW1zIHRvIGJlIGEgaGlnaGVyIGNvbmNlbnRyYXRpb24gb2YgUlNJIG1lYXN1cmVtZW50cyB0aGF0IGFyZSBhdCBsZWFzdCBhYm92ZSAxIHN0YW5kYXJkIGRldmlhdGlvbiBmcm9tIHRoZSBtZWFuIGluIHRoZSBsYXN0IDUgbWVhc3VyZW1lbnRzIG9mIHRoZSBzZWFzb24sIGFmdGVyIEZlYnJ1YXJ5IHN0YXJ0cyB0aGFuIGluIHRoZSByZXN0IG9mIHRoZSBzZWFzb24uIA0KVGhpcyBwbG90IHRob3VnaCwgZG9lcyBub3QgaGVscCB1cyB1bmRlcnN0YW5kIGhvdyBwbGF5ZXJzIHJlbGF0ZSB0byBlYWNoIG90aGVyLiBUaGlzIGNoYXJ0IGFsb25nIHdpdGggdGhlIGJveCBwbG90cyBvZiBlYWNoIHBsYXllcidzIFJTSSBtZWFzdXJlbWVudHMgc3VwcG9ydCB0aGUgY29uY2x1c2lvbiB0aGF0IGVhY2ggcGxheWVyIGhhcyBhIHZlcnkgdW5pcXVlIFJTSSBkaXN0cmlidXRpb24uIFRoZSBwbG90IGFib3ZlIGdldHMgYnJva2VuIGRvd24gYnkgZWFjaCBwbGF5ZXIgYmVsb3cuIA0KDQpgYGB7cn0NCiNjeWNsaW5nIHRocm91Z2ggYWxsIG9mIHRoZSBwbGF5ZXJzIGFuZCBwbG90dGluZyB0aGVpciBSU0kgbWVhc3VyZW1lbnRzIHRocm91Z2hvdXQgdGhlIHNlYXNvbg0KZm9yKGkgaW4gMToxMSl7DQogICNwbG90IHRoZSBtZWFzdXJlZCBSU0kgZm9yIGVhY2ggcGxheWVyIHRocm91Z2hvdXQgdGhlIHNlYXNvbg0KICAjZGFyayBncmVlbiBtZWFucyBwb2ludCBpcyBhYm92ZSAxIHN0YW5kYXJkIGRldmlhdGlvbiBmcm9tIG1lYW4NCiNsaWdodCBncmVlbiBtZWFucyBwb2ludCBpcyBhYm92ZSAyIHN0YW5kYXJkIGRldmlhdGlvbnMgZnJvbSBtZWFuDQojZGFyayByZWQgbWVhbnMgcG9pbnQgaXMgYmVsb3cgMSBzdGFuZGFyZCBkZXZpYXRpb24gZnJvbSBtZWFuDQojbGlnaHQgcmVkIG1lYW5zIHBvaW50IGlzIGJlbG93IDIgc3RhbmRhcmQgZGV2aWF0aW9ucyBmcm9tIG1lYW4NCnAgPC0gZ2dwbG90KGRhdGE9VkFMRF9Gb3JjZURlY2tzX2NsZWFuW1ZBTERfRm9yY2VEZWNrc19jbGVhbiRhbm9uX2lkID09IElEc1tpXSxdLCBhZXMoeD1EYXRlLCBQbGF5ZXIuQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gaWZlbHNlKFZBTERfRm9yY2VEZWNrc19jbGVhbltWQUxEX0ZvcmNlRGVja3NfY2xlYW4kYW5vbl9pZCA9PSBJRHNbaV0sXSRQbGF5ZXIuQWJvdmUuMi5TRCA9PSAxLCAicGFsZWdyZWVuIiwgaWZlbHNlKFZBTERfRm9yY2VEZWNrc19jbGVhbltWQUxEX0ZvcmNlRGVja3NfY2xlYW4kYW5vbl9pZCA9PSBJRHNbaV0sXSRQbGF5ZXIuQmVsb3cuMi5TRCA9PSAxLCAicmVkIiwgaWZlbHNlKFZBTERfRm9yY2VEZWNrc19jbGVhbltWQUxEX0ZvcmNlRGVja3NfY2xlYW4kYW5vbl9pZCA9PSBJRHNbaV0sXSRQbGF5ZXIuQmVsb3cuMS5TRCA9PSAxLCAicmVkNCIsIGlmZWxzZShWQUxEX0ZvcmNlRGVja3NfY2xlYW5bVkFMRF9Gb3JjZURlY2tzX2NsZWFuJGFub25faWQgPT0gSURzW2ldLF0kUGxheWVyLkFib3ZlLjEuU0QgPT0gMSwgInBhbGVncmVlbjQiLCAiZ3JleTcwIikpKSkpICsNCiAgeWxpbSgwLjczMTE0MDQsIDIuOTYzOTI1KSArDQogIGxhYnModGl0bGUgPSAiTWVhc3VyZWQgUlNJIFZhbHVlcyBUaHJvdWdob3V0IHRoZSBTZWFzb24gYW5kIFRoZWlyIFNpZ25pZmljYW5jZSIsIHN1YnRpdGxlID0gSURzW2ldKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpwcmludChwKQ0KfQ0KYGBgDQpUaGUgcGxvdHMgYWJvdmUgaGVscCB1cyB0byBzZWUgdGhhdCB0aGUgUlNJIGRpc3RyaWJ1dGlvbnMgZm9yIGVhY2ggcGxheWVyIGFyZSBnb2luZyB0byBiZSB3aWxkbHkgZGlmZmVyZW50IGZyb20gZWFjaCBvdGhlci4gSW4gZmFjdCwgc29tZSBvZiB0aGUgcGxvdHMgaGF2ZSBubyBvdmVybGFwIHdpdGggZWFjaCBvdGhlciAoZS5nLiBJRF81IGFuZCBJRF83NCkuIFRoaXMgc3VnZ2VzdHMgdGhhdCBkZWZpbmluZyBvbmUgc2luZ3VsYXIgdGhyZXNob2xkIGZvciB3aGF0IGlzIGEgbWVhbmluZ2Z1bCBjaGFuZ2UgaW4gUlNJIHdpbGwgbm90IGJlIGFjY3VyYXRlIGZvciBhbGwgb2YgdGhlIHBsYXllcnMuIA0KVGhlc2UgcGxvdHMgd2hlbiBsb29rZWQgYXQgYWxsIHRvZ2V0aGVyIGFsc28gaGVscCB1cyB0byBzZWUgdGhhdCB3aGVuIHBsYXllcnMgaGF2ZSBhbiBSU0kgbWVhc3VyZW1lbnQgdGhhdCBpcyBiZWxvdyBvbmUgc3RhbmRhcmQgZGV2aWF0aW9uIGZyb20gdGhlaXIgbWVhbiwgaXQgaXMgdXN1YWxseSBhc3NvY2lhdGVkIHdpdGggYW5vdGhlciBtZWFzdXJlbWVudCB0aGF0IGlzIGJlbG93IG9uZSBzdGFuZGFyZCBkZXZpYXRpb24gZWl0aGVyIGRpcmVjdGx5IG9yIGluIHRoZSBmb2xsb3dpbmcgdHdvIG9yIHRocmVlIG1lYXN1cmVtZW50cyBiZWZvcmUgcmV0dXJuaW5nIHRvIGEgbWVhc3VyZW1lbnQgdGhhdCBpcyBjbG9zZSB0byB0aGVpciBzZWFzb24gbWVhbi4gVGhpcyBpcyBub3QgdHJ1ZSBmb3IgYWxsIHBsYXllcnMgYnV0IHNlZW1zIHRvIGJlIHRydWUgZm9yIG1vc3Qgb2YgdGhlIHBsYXllcnMuIFRoaXMgc3VnZ2VzdHMgdGhhdCBmb3IgbW9zdCBvZiB0aGUgdGVhbSB0aGUgcmVjb3ZlcnkgdGltZSBmb3IgbmV1cm9tdXNjdWxhciBmYXRpZ3VlIHRoYXQgcmVzdWx0cyBpbiBhIG5vdGljZWFibHkgbG93ZXIgUlNJIHNjb3JlLCBtaWdodCBiZSBhcm91bmQgOCB0byAxMCBkYXlzIGdpdmVuIHRoYXQgUlNJIG1lYXN1cmVtZW50cyBhcmUgdGFrZW4gZXZlcnkgNCB0byA1IGRheXMgb24gYXZlcmFnZS4gDQoNCmBgYHtyIGNhbGN1bGF0aW5nIGhvdyBtYW55IHBsYXllcnMgd2VyZSBhYm92ZSBvciBiZWxvdyB0aGVpciBtZWFucyBhbmQgYnkgaG93IG11Y2ggZm9yIGVhY2ggZGF0ZX0NClZBTERfRm9yY2VEZWNrc19jbGVhbiA8LSBWQUxEX0ZvcmNlRGVja3NfY2xlYW4gJT4lDQogIGdyb3VwX2J5KERhdGUpICU+JQ0KICAjbWFraW5nIDQgbmV3IGNvbHVtbnMgdGhhdCB3aWxsIGNvdW50IGhvdyBtYW55IHBsYXllcnMgd2VyZSBpbiBlYWNoIGNhdGVnb3J5IGZvciBlYWNoIGRhdGUNCiAgbXV0YXRlKE51bS5BYm92ZS4xU0QgPSByb3VuZChtZWFuKFBsYXllci5BYm92ZS4xLlNEKSpsZW5ndGgodW5pcXVlKGFub25faWQpKSksDQogICAgICAgICBOdW0uQmVsb3cuMVNEID0gcm91bmQobWVhbihQbGF5ZXIuQmVsb3cuMS5TRCkqbGVuZ3RoKHVuaXF1ZShhbm9uX2lkKSkpLA0KICAgICAgICAgTnVtLkFib3ZlLjJTRCA9IHJvdW5kKG1lYW4oUGxheWVyLkFib3ZlLjIuU0QpKmxlbmd0aCh1bmlxdWUoYW5vbl9pZCkpKSwNCiAgICAgICAgIE51bS5CZWxvdy4yU0QgPSByb3VuZChtZWFuKFBsYXllci5CZWxvdy4yLlNEKSpsZW5ndGgodW5pcXVlKGFub25faWQpKSkpICU+JQ0KICB1bmdyb3VwKCkNCmBgYA0KDQpgYGB7ciBQbG90dGluZyB0aGUgZnJlcXVlbmN5IG9mIFJTSSBtZWFzdXJlbWVudHMgdGhhdCB3ZXJlIGJlbG93IG9yIGFib3ZlIG1lYW59DQojdGFraW5nIG91dCB0aGUgZGF0ZXMgdGhhdCBhcmUgZm91bmQgaW4gdGhlIGRhdGEgc2V0DQpEYXRlcyA8LSB1bmlxdWUoVkFMRF9Gb3JjZURlY2tzX2NsZWFuJERhdGUpDQpyb3dzIDwtIHJlcChOQSwgMjIpDQoNCiNnbyB0aHJvdWdoIHRoZSBkYXRhIHNldCBhbmQgdGFrZSB0aGUgZmlyc3Qgcm93IGZvdW5kIGZvciBlYWNoIGRhdGUuIFRoZXJlIGlzIG9ubHkgMSBvYnNlcnZhdGlvbiBmb3IgZWFjaCBkYXRlIGJlY2F1c2Ugd2Ugb25seSB3YW50IHRoZSB0b3RhbHMgc28gbm8gZGF0YSBpcyBsb3N0DQpmb3IoaSBpbiAxOjIyKXsNCiAgcm93c1tpXSA8LSBtaW4oVkFMRF9Gb3JjZURlY2tzX2NsZWFuW1ZBTERfRm9yY2VEZWNrc19jbGVhbiREYXRlID09IERhdGVzW2ldLF0kWCkNCn0NCiN0YWtpbmcgb3V0IHRoZSByb3dzIGZyb20gdGhlIGRhdGEgc2V0IHRoYXQgd2UgbmVlZA0KdGVzdCA8LSBWQUxEX0ZvcmNlRGVja3NfY2xlYW5bVkFMRF9Gb3JjZURlY2tzX2NsZWFuJFggJWluJSByb3dzLF0NCg0KI3Bsb3R0aW5nIHRoZSBudW1iZXIgb2YgcGxheWVycyB0aGF0IGhhZCBhbiBSU0kgbWVhc3VyZW1lbnQgYXQgbGVhc3QgMSBTRCBhYm92ZSB0aGVpciBzZWFzb24gbWVhbiB3aXRoIGRhdGUgb24gdGhlIHggYXhpcyBpbiBhIGJhciBjaGFydA0KZ2dwbG90KGRhdGE9dGVzdCwgYWVzKHg9RGF0ZSkpICsNCiAgZ2VvbV9jb2woYWVzKHk9TnVtLkFib3ZlLjFTRCksIGZpbGwgPSAicGFsZWdyZWVuNCIpICsNCiAgZ2VvbV9jb2woYWVzKHk9TnVtLkFib3ZlLjJTRCksIGZpbGwgPSAicGFsZWdyZWVuIikgKw0KICB5bGltKDAsNykgKw0KICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBQbGF5ZXJzIEFib3ZlIFRoZWlyIE1lYW4gU2Vhc29uIFJTSSBNZWFzdXJlbWVudCIsDQogICAgICAgeT0iTnVtYmVyIEFib3ZlIE1lYW4gUlNJIE1lYXN1cmVtZW50IikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KI3Bsb3R0aW5nIHRoZSBudW1iZXIgb2YgcGxheWVycyB0aGF0IGhhZCBhbiBSU0kgbWVhc3VyZW1lbnQgYXQgbGVhc3QgMiBTRCBiZWxvdyB0aGVpciBzZWFzb24gbWVhbiB3aXRoIGRhdGUgb24gdGhlIHggYXhpcyBpbiBhIGJhciBjaGFydA0KZ2dwbG90KGRhdGE9dGVzdCwgYWVzKHg9RGF0ZSkpICsNCiAgZ2VvbV9jb2woYWVzKHk9TnVtLkJlbG93LjFTRCksIGZpbGwgPSAicmVkNCIpICsNCiAgZ2VvbV9jb2woYWVzKHk9TnVtLkJlbG93LjJTRCksIGZpbGwgPSAicmVkIikgKw0KICB5bGltKDAsNykrDQogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIFBsYXllcnMgQmVsb3cgVGhlaXIgTWVhbiBTZWFzb24gUlNJIE1lYXN1cmVtZW50IiwNCiAgICAgICB5PSJOdW1iZXIgQmVsb3cgTWVhbiBSU0kgTWVhc3VyZW1lbnQiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQpGcm9tIHRoZSBwbG90cyBhYm92ZSwgd2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSB0d28gZ2VuZXJhbCBwYXJ0cyBvZiB0aGUgc2Vhc29uIGluIHdoaWNoIHRoZSB0ZWFtIGhhcyBtb3JlIGZyZXF1ZW50IGRyb3BzIGluIFJTSSBhbmQgdGhlIHRlYW0gaGFzIG1vcmUgZnJlcXVlbnQgZ2FpbnMgaW4gUlNJLiBUaGVzZSBwbG90cyBtYWtlIGl0IGVhc3kgdG8gc2VlIHRoYXQgdGhlIHRlYW0gaGFkIGEgbG90IG1vcmUgZnJlcXVlbnQgZHJvcHMgaW4gUlNJIGluIHRoZSBiZWdpbm5pbmcgb2YgdGhlIHNlYXNvbiB0aGFuIGF0IHRoZSBlbmQgb2YgdGhlIHNlYXNvbi4gSW4gZmFjdCwgdGhlIGxhc3QgbWFqb3IgZHJvcCBmb3IgYW55IHBsYXllciBvbiB0aGUgdGVhbSBoYXBwZW5lZCBhdCB0aGUgZW5kIG9mIEphbnVhcnkgYW5kIHRoZXJlIGFyZSBubyBtb3JlIGRyb3BzIGZvciB0aGUgcmVzdCBvZiB0aGUgc2Vhc29uLiBXaXRoIHRoaXMsIHdlIHNlZSB0aGF0IFJTSSBnYWlucyBhcmUgbm90IGFzIGNvbW1vbiB0aHJvdWdob3V0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHNlYXNvbi4gV2Ugb25seSBzZWUgb25lIG9yIHR3byBwbGF5ZXJzIHRoYXQgaGF2ZSBhbiBSU0kgbWVhc3VyZW1lbnQgYWJvdmUgb25lIG9yIHR3byBzdGFuZGFyZCBkZXZpYXRpb25zIGFib3ZlIHRoZWlyIG1lYW4gdW50aWwgRmVicnVhcnkuIEl0IGlzIG9ubHkgb25jZSBGZWJydWFyeSBzdGFydHMgdGhhdCB3ZSBzZWUgYW4gaW5jcmVhc2UgaW4gdGhlIG51bWJlciBvZiBwbGF5ZXJzIHRoYXQgaGF2ZSBhbiBSU0kgYXQgbGVhc3Qgb25lIHN0YW5kYXJkIGRldmlhdGlvbiBhYm92ZSB0aGVpciBtZWFuLiANCg0KDQojIyMjIExvb2tpbmcgYXQgcGxheWVyIGF2ZXJhZ2UgUlNJIHZhbHVlcw0KYGBge3J9DQojY2FsY3VsYXRpbmcgdGhlIG1lYW4gYW5kIHZhcmlhbmNlIG9mIFJTSSBmb3IgdGhlIHBsYXllcnMgdGhyb3VnaG91dCB0aGUgc2Vhc29uDQp0ZWFtX21lYW4gPC0gbWVhbihWQUxEX0ZvcmNlRGVja3NfY2xlYW4kUGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLikNCnRlYW1fdmFyIDwtIHNhbXBsZV9tZWFuX2FuZF92YXJpYW5jZShWQUxEX0ZvcmNlRGVja3NfY2xlYW4kUGxheWVyLkF2ZXJhZ2UuUlNJLi5tLnBlci5zLilbWzJdXQ0KDQojcGxvdHRpbmcgUlNJIG1lYXN1cmVtZW50cyB0aHJvdWdob3V0IHRoZSBzZWFzb24sIGFkZGluZyBpbiB0aGUgbWVhbiBSU0kgdmFsdWUgYW5kIDEgc3RhbmRhcmQgZGV2aWF0aW9uIGFib3ZlIGFuZCBiZWxvdyB0aGUgbWVhbg0KZ2dwbG90KFZBTERfRm9yY2VEZWNrc19jbGVhbiwgYWVzKHg9RGF0ZSwgeT1QbGF5ZXIuQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSB0ZWFtX21lYW4pICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gdGVhbV9tZWFuIC0gc3FydCh0ZWFtX3ZhciksIGNvbG9yPSIjQ0ZCODdDIikgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSB0ZWFtX21lYW4gKyBzcXJ0KHRlYW1fdmFyKSwgY29sb3I9IiNDRkI4N0MiKQ0KDQojcGxvdHRpbmcgdGhlIFJTSSB2YWx1ZXMgdGhyb3VnaG91dCB0aGUgc2Vhc29uIGFuZCBwbG90dGluZyB0aGUgdGVhbSBSU0kgdHJlbmQgb3ZlcnRvcCB0byBzZWUgaWYgdGhlcmUgYXJlIHVuZGVyeWluZyB0cmVuZHMgdGhhdCBjb3VsZCBiZSBleHBsYWluZWQgd2l0aCB0aGUgdGVhbSB0cmVuZA0KZ2dwbG90KFZBTERfRm9yY2VEZWNrc19jbGVhbiwgYWVzKHg9RGF0ZSwgeT1QbGF5ZXIuQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX2xpbmUoZGF0YT1WQUxEX0ZvcmNlRGVja3NfY2xlYW4sIGFlcyhEYXRlLFRlYW0uQXZlcmFnZS5SU0kuLm0ucGVyLnMuKSwgY29sb3IgPSAiI0NGQjg3QyIpDQpgYGANCg0KDQpgYGB7cn0NCg0KI2N5Y2xlIHRocm91Z2ggYWxsIG9mIHRoZSBwbGF5ZXJzDQpmb3IoaSBpbiAxOjExKXsNCiAgI21ha2luZyBhIHBsb3Qgd2l0aCBkYXRlIG9uIHggYXhpcyBhbmQgYXZlcmFnZSA3IGRheSBqdW1wIGxvYWQgb24gdGhlIHkgYXhpcyB0byBzZWUgaWYgdGhlcmUgaXMgcG90ZW50aWFsbHkgYW55IHJlbGF0aW9uc2hpcCBpbiB0aGUgdHJlbmQgb2YgdGhlIGxvYWQgYW5kIGNoYW5nZXMgaW4gUlNJDQpyIDwtIGdncGxvdChyb2xsaW5nX05EYXlfbG9hZFtyb2xsaW5nX05EYXlfbG9hZCRhbm9uX2lkID09IElEc1tpXSxdLCBhZXMoeD1EYXRlLCB5PVRvdGFsLi43RGF5Li5KdW1wLkxvYWQpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHlsaW0oMCwgNDAwMDAwKSArDQogIGxhYnModGl0bGU9Ikp1bXAgTG9hZHMgdGhyb3VnaCB0aGUgU2Vhc29uIiwgc3VidGl0bGUgPSBJRHNbaV0pICsNCiAgI2NhbGN1bGF0aW5nIGEgbW92aW5nIGF2ZXJhZ2UgdG8gYmV0dGVyIHNlZSB0aGUgdW5kZXJseWluZyBzaGFwZSBvZiB0aGUgZGF0YQ0KICBnZW9tX2xpbmUoeT1tb3ZpbmdfYXZlcmFnZShyb2xsaW5nX05EYXlfbG9hZFtyb2xsaW5nX05EYXlfbG9hZCRhbm9uX2lkID09IElEc1tpXSxdJFRvdGFsLi43RGF5Li5KdW1wLkxvYWQsMyksDQogICAgICAgICAgICBjb2xvciA9ICIjQ0ZCODdDIikgKw0KICANCiAgI2FkZGluZyBpbiB2ZXJ0aWNhbCBsaW5lcyB0aGF0IHJlcHJlc2VudCB0aGUgZGF0ZXMgaW4gd2hpY2ggdGhlIHBsYXllciBoYWQgYW4gUlNJIG1lYXN1cmVtZW50IGFib3ZlIG9yIGJlbG93IHRoZWlyIG1lYW4gYnkgYXQgbGVhc3QgMSBTRC4gU2FtZSBjb2xvciBwYWxldHRlIGFwcGxpZXMNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gVkFMRF9Gb3JjZURlY2tzX2NsZWFuW1ZBTERfRm9yY2VEZWNrc19jbGVhbiRhbm9uX2lkPT1JRHNbaV0gJiBWQUxEX0ZvcmNlRGVja3NfY2xlYW4kUGxheWVyLkFib3ZlLjEuU0Q9PTEsXSREYXRlLCBjb2xvciA9ICJwYWxlZ3JlZW40IikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBWQUxEX0ZvcmNlRGVja3NfY2xlYW5bVkFMRF9Gb3JjZURlY2tzX2NsZWFuJGFub25faWQ9PUlEc1tpXSAmIFZBTERfRm9yY2VEZWNrc19jbGVhbiRQbGF5ZXIuQWJvdmUuMi5TRD09MSxdJERhdGUsIGNvbG9yID0gInBhbGVncmVlbiIpICsgDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IFZBTERfRm9yY2VEZWNrc19jbGVhbltWQUxEX0ZvcmNlRGVja3NfY2xlYW4kYW5vbl9pZD09SURzW2ldICYgVkFMRF9Gb3JjZURlY2tzX2NsZWFuJFBsYXllci5CZWxvdy4xLlNEPT0xLF0kRGF0ZSwgY29sb3IgPSAicmVkNCIpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gVkFMRF9Gb3JjZURlY2tzX2NsZWFuW1ZBTERfRm9yY2VEZWNrc19jbGVhbiRhbm9uX2lkPT1JRHNbaV0gJiBWQUxEX0ZvcmNlRGVja3NfY2xlYW4kUGxheWVyLkJlbG93LjIuU0Q9PTEsXSREYXRlLCBjb2xvciA9ICJyZWQiKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG1lYW4ocm9sbGluZ19ORGF5X2xvYWRbcm9sbGluZ19ORGF5X2xvYWQkYW5vbl9pZCA9PSBJRHNbaV0sXSRUb3RhbC4uN0RheS4uSnVtcC5Mb2FkKSkNCg0KcHJpbnQocikNCn0NCmBgYA0KDQpMb29raW5nIGF0IHRoZSBwbG90cyBhYm92ZSwgdGhlcmUgZG9lcyBub3Qgc2VlbSB0byBiZSBhIGNsZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIFJTSSBtZWFzdXJlbWVudHMgYW5kIGxvYWRpbmcgc3VtbWFyaXplZCBieSBhbnkgbGVuZ3RoICgyLDMsNyBkYXlzKS4gVGhpcyBzdWdnZXN0cyB0aGF0IHRoZXJlIG1heSBoYXZlIGJlZW4gc29tZSBvdGhlciBjaGFuZ2UgaW4gdHJhaW5pbmcgdGhhdCBoYWQgYSBwb3NpdGl2ZSBpbXBhY3Qgb24gUlNJIG1lYXN1cmVtZW50cyBmb3IgdGhlIGVudGlyZSB0ZWFtLiBUaGlzIG1heSBiZSBkdWUgdG8gc29tZXRoaW5nIHRoYXQgaXMgbm90IGxvYWRpbmcgcmVsYXRlZC4gQmxha2Ugc2FpZCBpdCBtaWdodCBiZSBtb3JlIHRhcmdldGVkIGxpZnRzLiA=